private Function(Delegate @delegate, Type returnType, Type[] args, FunctionMValueParser[] parsers, FunctionObjectParser[] objectParsers, FunctionStringParser[] stringParsers, FunctionTypeInfo[] typeInfos, CallArgsLengthCheck callArgsLengthCheck, CallArgsLengthCheckPlayer callArgsLengthCheckPlayer, int requiredArgsCount) { this.@delegate = @delegate; this.returnType = returnType; this.args = args; this.parsers = parsers; this.objectParsers = objectParsers; this.stringParsers = stringParsers; this.typeInfos = typeInfos; this.callArgsLengthCheck = callArgsLengthCheck; this.callArgsLengthCheckPlayer = callArgsLengthCheckPlayer; this.requiredArgsCount = 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 //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)); }