//TODO: for high optimization add ParseBoolUnsafe ect. that doesn't contains the mValue type check for scenarios where we already had to check the mValue type //TODO: add support for own function arguments parser for significant performance improvements with all benefits // Returns null when function signature isn't supported public static Function Create <T>(T func) where T : Delegate { var type = func.GetType(); var genericArguments = type.GetGenericArguments(); Type returnType; if (type.Name.StartsWith("Func")) { // Return type is last generic argument // Function never has empty generic arguments, so no need for size check, but we do it anyway if (genericArguments.Length == 0) { returnType = FunctionTypes.Void; } else { returnType = genericArguments[genericArguments.Length - 1]; genericArguments = genericArguments.SkipLast(1).ToArray(); } } else { returnType = FunctionTypes.Void; } //TODO: check for unsupported types //TODO: check if last type is a object[] and add all to it that didnt fit with length, like (string bla, object[] args) //TODO: add parameter type attribute to annotate object[] with var parsers = new FunctionMValueParser[genericArguments.Length]; var objectParsers = new FunctionObjectParser[genericArguments.Length]; var stringParsers = new FunctionStringParser[genericArguments.Length]; var typeInfos = new FunctionTypeInfo[genericArguments.Length]; var requiredArgsCount = 0; for (int i = 0, length = genericArguments.Length; i < length; i++) { var arg = genericArguments[i]; var typeInfo = new FunctionTypeInfo(arg); typeInfos[i] = typeInfo; if (!typeInfo.IsNullable && !typeInfo.IsEventParams) { requiredArgsCount++; } if (arg == FunctionTypes.Obj) { //TODO: use MValue.ToObject here parsers[i] = FunctionMValueParsers.ParseObject; objectParsers[i] = FunctionObjectParsers.ParseObject; stringParsers[i] = FunctionStringParsers.ParseObject; } else if (arg == FunctionTypes.Bool) { parsers[i] = FunctionMValueParsers.ParseBool; objectParsers[i] = FunctionObjectParsers.ParseBool; stringParsers[i] = FunctionStringParsers.ParseBool; } else if (arg == FunctionTypes.Int) { parsers[i] = FunctionMValueParsers.ParseInt; objectParsers[i] = FunctionObjectParsers.ParseInt; stringParsers[i] = FunctionStringParsers.ParseInt; } else if (arg == FunctionTypes.Long) { parsers[i] = FunctionMValueParsers.ParseLong; objectParsers[i] = FunctionObjectParsers.ParseLong; stringParsers[i] = FunctionStringParsers.ParseLong; } else if (arg == FunctionTypes.UInt) { parsers[i] = FunctionMValueParsers.ParseUInt; objectParsers[i] = FunctionObjectParsers.ParseUInt; stringParsers[i] = FunctionStringParsers.ParseUInt; } else if (arg == FunctionTypes.ULong) { parsers[i] = FunctionMValueParsers.ParseULong; objectParsers[i] = FunctionObjectParsers.ParseULong; stringParsers[i] = FunctionStringParsers.ParseULong; } else if (arg == FunctionTypes.Float) { parsers[i] = FunctionMValueParsers.ParseFloat; objectParsers[i] = FunctionObjectParsers.ParseFloat; stringParsers[i] = FunctionStringParsers.ParseFloat; } else if (arg == FunctionTypes.Double) { parsers[i] = FunctionMValueParsers.ParseDouble; objectParsers[i] = FunctionObjectParsers.ParseDouble; stringParsers[i] = FunctionStringParsers.ParseDouble; } else if (arg == FunctionTypes.String) { parsers[i] = FunctionMValueParsers.ParseString; objectParsers[i] = FunctionObjectParsers.ParseString; stringParsers[i] = FunctionStringParsers.ParseString; } else if (arg.BaseType == FunctionTypes.Array) { parsers[i] = FunctionMValueParsers.ParseArray; objectParsers[i] = FunctionObjectParsers.ParseArray; stringParsers[i] = FunctionStringParsers.ParseArray; } else if (typeInfo.IsEntity) { parsers[i] = FunctionMValueParsers.ParseEntity; objectParsers[i] = FunctionObjectParsers.ParseEntity; stringParsers[i] = FunctionStringParsers.ParseEntity; } else if (typeInfo.IsDict) { parsers[i] = FunctionMValueParsers.ParseDictionary; objectParsers[i] = FunctionObjectParsers.ParseDictionary; stringParsers[i] = FunctionStringParsers.ParseDictionary; } else if (typeInfo.IsMValueConvertible) { parsers[i] = FunctionMValueParsers.ParseConvertible; objectParsers[i] = FunctionObjectParsers.ParseConvertible; stringParsers[i] = FunctionStringParsers.ParseConvertible; } else if (arg == FunctionTypes.FunctionType) { parsers[i] = FunctionMValueParsers.ParseFunction; objectParsers[i] = FunctionObjectParsers.ParseFunction; stringParsers[i] = FunctionStringParsers.ParseFunction; } else if (typeInfo.IsEnum) { parsers[i] = FunctionMValueParsers.ParseEnum; objectParsers[i] = FunctionObjectParsers.ParseEnum; } else { // Unsupported type return(null); } } for (int i = 0, length = typeInfos.Length; i < length; i++) { if (!typeInfos[i].IsNullable || i - 1 >= length) { continue; } if (!typeInfos[i + 1].IsNullable && !typeInfos[i + 1].IsEventParams) { throw new ArgumentException( "Method nullable needs to be at the end of the method. E.g. (int p1, int? p2, int p3?)."); } } CallArgsLengthCheck callArgsLengthCheck = CheckArgsLength; CallArgsLengthCheckPlayer callArgsLengthCheckPlayer = CheckArgsLengthWithPlayer; if (typeInfos.Length > 0) { var lastTypeInfo = typeInfos[typeInfos.Length - 1]; if (lastTypeInfo.IsEventParams) { if (lastTypeInfo.IsList) { throw new ArgumentException("EventParams needs to be a array."); } callArgsLengthCheck = CheckArgsLengthWithEventParams; callArgsLengthCheckPlayer = CheckArgsLengthWithPlayerWithEventParams; } } return(new Function(func, returnType, genericArguments, parsers, objectParsers, stringParsers, typeInfos, callArgsLengthCheck, callArgsLengthCheckPlayer, requiredArgsCount)); }
/*private delegate bool CallArgsLengthCheck(Type[] args, int requiredArgsCount, FunctionTypeInfo[] typeInfos, * MValueConst[] values); * * private delegate bool CallArgsLengthCheckPlayer(Type[] args, int requiredArgsCount, * FunctionTypeInfo[] typeInfos, IPlayer player, * MValueConst[] values);*/ //TODO: for high optimization add ParseBoolUnsafe ect. that doesn't contains the mValue type check for scenarios where we already had to check the mValue type // Returns null when function signature isn't supported public static Function Create <T>(T func) where T : Delegate { var genericArguments = func.GetType().GetGenericArguments(); var parameters = func.Method.GetParameters(); var returnType = func.Method.ReturnType; if (returnType != FunctionTypes.Void) { genericArguments = genericArguments.SkipLast(1).ToArray(); } //TODO: check for unsupported types var constParsers = new FunctionMValueConstParser[parameters.Length]; var objectParsers = new FunctionObjectParser[parameters.Length]; var stringParsers = new FunctionStringParser[parameters.Length]; var typeInfos = new FunctionTypeInfo[parameters.Length]; var requiredArgsCount = 0; for (int i = 0, length = parameters.Length; i < length; i++) { var parameterInfo = parameters[i]; var arg = parameterInfo.ParameterType; var typeInfo = typeInfos[i] = new FunctionTypeInfo(arg, parameterInfo); if (!typeInfo.IsNullable && !typeInfo.IsParamArray && !parameterInfo.HasDefaultValue) { requiredArgsCount++; } constParsers[i] = typeInfo.ConstParser; objectParsers[i] = typeInfo.ObjectParser; stringParsers[i] = typeInfo.StringParser; if (constParsers[i] == null || objectParsers[i] == null || stringParsers[i] == null) { // Unsupported type return(null); } } for (int i = 0, length = typeInfos.Length; i < length; i++) { if (typeInfos[i].IsParamArray && i + 1 < length) { throw new ArgumentException( "params array needs to be at the end of the method. E.g. (int p1, int p2, params int[] args)"); } if (!typeInfos[i].IsNullable || i + 1 >= length) { continue; } if (!typeInfos[i + 1].IsNullable && !typeInfos[i + 1].IsParamArray) { throw new ArgumentException( "Method nullable needs to be at the end of the method. E.g. (int p1, int? p2, int p3?)."); } } return(new Function(func, returnType, genericArguments, constParsers, objectParsers, stringParsers, typeInfos, requiredArgsCount)); }
//TODO: for high optimization add ParseBoolUnsafe ect. that doesn't contains the mValue type check for scenarios where we already had to check the mValue type //TODO: add support for own function arguments parser for significant performance improvements with all benefits // Returns null when function signature isn't supported public static Function Create <T>(T func) where T : Delegate { var type = func.GetType(); var genericArguments = type.GetGenericArguments(); Type returnType; if (type.Name.StartsWith("Func")) { // Return type is last generic argument // Function never has empty generic arguments, so no need for size check, but we do it anyway if (genericArguments.Length == 0) { returnType = FunctionTypes.Void; } else { returnType = genericArguments[genericArguments.Length - 1]; genericArguments = genericArguments.SkipLast(1).ToArray(); } } else { returnType = FunctionTypes.Void; } //TODO: check for unsupported types var parsers = new FunctionMValueParser[genericArguments.Length]; var objectParsers = new FunctionObjectParser[genericArguments.Length]; var typeInfos = new FunctionTypeInfo[genericArguments.Length]; for (int i = 0, length = genericArguments.Length; i < length; i++) { var arg = genericArguments[i]; var typeInfo = new FunctionTypeInfo(arg); typeInfos[i] = typeInfo; if (arg == FunctionTypes.Obj) { //TODO: use MValue.ToObject here parsers[i] = FunctionMValueParsers.ParseObject; objectParsers[i] = FunctionObjectParsers.ParseObject; } else if (arg == FunctionTypes.Bool) { parsers[i] = FunctionMValueParsers.ParseBool; objectParsers[i] = FunctionObjectParsers.ParseBool; } else if (arg == FunctionTypes.Int) { parsers[i] = FunctionMValueParsers.ParseInt; objectParsers[i] = FunctionObjectParsers.ParseInt; } else if (arg == FunctionTypes.Long) { parsers[i] = FunctionMValueParsers.ParseLong; objectParsers[i] = FunctionObjectParsers.ParseLong; } else if (arg == FunctionTypes.UInt) { parsers[i] = FunctionMValueParsers.ParseUInt; objectParsers[i] = FunctionObjectParsers.ParseUInt; } else if (arg == FunctionTypes.ULong) { parsers[i] = FunctionMValueParsers.ParseULong; objectParsers[i] = FunctionObjectParsers.ParseULong; } else if (arg == FunctionTypes.Float) { parsers[i] = FunctionMValueParsers.ParseFloat; objectParsers[i] = FunctionObjectParsers.ParseFloat; } else if (arg == FunctionTypes.Double) { parsers[i] = FunctionMValueParsers.ParseDouble; objectParsers[i] = FunctionObjectParsers.ParseDouble; } else if (arg == FunctionTypes.String) { parsers[i] = FunctionMValueParsers.ParseString; objectParsers[i] = FunctionObjectParsers.ParseString; } else if (arg.BaseType == FunctionTypes.Array) { parsers[i] = FunctionMValueParsers.ParseArray; objectParsers[i] = FunctionObjectParsers.ParseArray; } else if (typeInfo.IsEntity) { parsers[i] = FunctionMValueParsers.ParseEntity; objectParsers[i] = FunctionObjectParsers.ParseEntity; } else if (typeInfo.IsDict) { parsers[i] = FunctionMValueParsers.ParseDictionary; objectParsers[i] = FunctionObjectParsers.ParseDictionary; } else if (arg == FunctionTypes.FunctionType) { parsers[i] = FunctionMValueParsers.ParseFunction; objectParsers[i] = FunctionObjectParsers.ParseFunction; } else { // Unsupported type return(null); } } return(new Function(func, returnType, genericArguments, parsers, objectParsers, typeInfos)); }