/*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)); }
public FunctionTypeInfo(Type paramType, ParameterInfo paramInfo = null) { var param = Expression.Parameter(typeof(int)); CreateArrayOfElementType = Expression.Lambda <Func <int, Array> >( Expression.NewArrayBounds(paramType, param), param).Compile(); IsList = paramType.BaseType == FunctionTypes.Array; IsDict = paramType.Name.StartsWith("Dictionary") || paramType.Name.StartsWith("IDictionary"); if (IsDict) { GenericArguments = paramType.GetGenericArguments(); //TODO: dont create this for primitive type dictionaries DictType = typeof(Dictionary <,>).MakeGenericType(GenericArguments[0], GenericArguments[1]); DictionaryValue = GenericArguments.Length == 2 ? new FunctionTypeInfo(GenericArguments[1]) : null; CreateDictionary = Expression.Lambda <Func <IDictionary> >( Expression.New(DictType) ).Compile(); } else { GenericArguments = null; DictType = null; DictionaryValue = null; CreateDictionary = null; } if (paramInfo != null && paramInfo.HasDefaultValue) { DefaultValue = paramInfo.DefaultValue; } else { if (paramType.IsValueType && paramType != FunctionTypes.String) { DefaultValue = Activator.CreateInstance(paramType); } else { DefaultValue = null; } } IsPosition = paramType == FunctionTypes.Position; IsRotation = paramType == FunctionTypes.Rotation; IsRgba = paramType == FunctionTypes.Rgba; IsVector3 = paramType == FunctionTypes.Vector3; IsByteArray = paramType == FunctionTypes.ByteArray; var interfaces = paramType.GetInterfaces(); if (interfaces.Contains(FunctionTypes.BaseObject)) { IsBaseObject = true; IsVehicle = paramType == FunctionTypes.Vehicle || interfaces.Contains(FunctionTypes.Vehicle); IsPlayer = paramType == FunctionTypes.Player || interfaces.Contains(FunctionTypes.Player); } else { IsBaseObject = false; IsVehicle = false; IsPlayer = false; } IsMValueConvertible = interfaces.Contains(FunctionTypes.MValueConvertible); var elementType = paramType.GetElementType(); if (elementType != null) { ElementType = elementType; Element = new FunctionTypeInfo(elementType); var arraySizeParam = Expression.Parameter(typeof(int)); CreateArrayOfTypeExp = Expression.Lambda <Func <int, Array> >( Expression.NewArrayBounds(ElementType, arraySizeParam), new[] { arraySizeParam } ).Compile(); EmptyArrayOfType = Array.CreateInstance(ElementType, 0); } else { CreateArrayOfTypeExp = null; EmptyArrayOfType = null; } if (paramInfo != null) { IsParamArray = paramInfo.GetCustomAttribute <ParamArrayAttribute>() != null; } IsNullable = paramType.Name.StartsWith("Nullable"); if (IsNullable) { var genericArguments = paramType.GetGenericArguments(); if (genericArguments.Length != 1) { IsNullable = false; } else { NullableType = genericArguments[0]; DefaultValue = Activator.CreateInstance(typeof(Nullable <>).MakeGenericType(NullableType)); } } IsEnum = paramType.IsEnum; if (IsNullable) { paramType = NullableType; } if (paramType == FunctionTypes.Obj) { ConstParser = FunctionMValueConstParsers.ParseObject; ObjectParser = FunctionObjectParsers.ParseObject; StringParser = FunctionStringParsers.ParseObject; } else if (paramType == FunctionTypes.Bool) { ConstParser = FunctionMValueConstParsers.ParseBool; ObjectParser = FunctionObjectParsers.ParseBool; StringParser = FunctionStringParsers.ParseBool; } else if (paramType == FunctionTypes.SByte) { ConstParser = FunctionMValueConstParsers.ParseSByte; ObjectParser = FunctionObjectParsers.ParseSByte; StringParser = FunctionStringParsers.ParseSByte; } else if (paramType == FunctionTypes.Short) { ConstParser = FunctionMValueConstParsers.ParseShort; ObjectParser = FunctionObjectParsers.ParseShort; StringParser = FunctionStringParsers.ParseShort; } else if (paramType == FunctionTypes.Int) { ConstParser = FunctionMValueConstParsers.ParseInt; ObjectParser = FunctionObjectParsers.ParseInt; StringParser = FunctionStringParsers.ParseInt; } else if (paramType == FunctionTypes.Long) { ConstParser = FunctionMValueConstParsers.ParseLong; ObjectParser = FunctionObjectParsers.ParseLong; StringParser = FunctionStringParsers.ParseLong; } else if (paramType == FunctionTypes.Byte) { ConstParser = FunctionMValueConstParsers.ParseByte; ObjectParser = FunctionObjectParsers.ParseByte; StringParser = FunctionStringParsers.ParseByte; } else if (paramType == FunctionTypes.UShort) { ConstParser = FunctionMValueConstParsers.ParseUShort; ObjectParser = FunctionObjectParsers.ParseUShort; StringParser = FunctionStringParsers.ParseUShort; } else if (paramType == FunctionTypes.UInt) { ConstParser = FunctionMValueConstParsers.ParseUInt; ObjectParser = FunctionObjectParsers.ParseUInt; StringParser = FunctionStringParsers.ParseUInt; } else if (paramType == FunctionTypes.ULong) { ConstParser = FunctionMValueConstParsers.ParseULong; ObjectParser = FunctionObjectParsers.ParseULong; StringParser = FunctionStringParsers.ParseULong; } else if (paramType == FunctionTypes.Float) { ConstParser = FunctionMValueConstParsers.ParseFloat; ObjectParser = FunctionObjectParsers.ParseFloat; StringParser = FunctionStringParsers.ParseFloat; } else if (paramType == FunctionTypes.Double) { ConstParser = FunctionMValueConstParsers.ParseDouble; ObjectParser = FunctionObjectParsers.ParseDouble; StringParser = FunctionStringParsers.ParseDouble; } else if (paramType == FunctionTypes.String) { ConstParser = FunctionMValueConstParsers.ParseString; ObjectParser = FunctionObjectParsers.ParseString; StringParser = FunctionStringParsers.ParseString; } else if (paramType.BaseType == FunctionTypes.Array) { ConstParser = FunctionMValueConstParsers.ParseArray; ObjectParser = FunctionObjectParsers.ParseArray; StringParser = FunctionStringParsers.ParseArray; } else if (IsBaseObject) { ConstParser = FunctionMValueConstParsers.ParseBaseObject; ObjectParser = FunctionObjectParsers.ParseBaseObject; StringParser = FunctionStringParsers.ParseBaseObject; } else if (IsDict) { ConstParser = FunctionMValueConstParsers.ParseDictionary; ObjectParser = FunctionObjectParsers.ParseDictionary; StringParser = FunctionStringParsers.ParseDictionary; } else if (IsMValueConvertible) { ConstParser = FunctionMValueConstParsers.ParseConvertible; ObjectParser = FunctionObjectParsers.ParseConvertible; StringParser = FunctionStringParsers.ParseConvertible; } else if (paramType == FunctionTypes.FunctionType) { ConstParser = FunctionMValueConstParsers.ParseFunction; ObjectParser = FunctionObjectParsers.ParseFunction; StringParser = FunctionStringParsers.ParseFunction; } else if (IsEnum) { ConstParser = FunctionMValueConstParsers.ParseEnum; ObjectParser = FunctionObjectParsers.ParseEnum; StringParser = FunctionStringParsers.ParseEnum; } else if (IsPosition) { ConstParser = FunctionMValueConstParsers.ParsePosition; ObjectParser = FunctionObjectParsers.ParsePosition; StringParser = FunctionStringParsers.ParsePosition; } else if (IsRotation) { ConstParser = FunctionMValueConstParsers.ParseRotation; ObjectParser = FunctionObjectParsers.ParseRotation; StringParser = FunctionStringParsers.ParseRotation; } else if (IsVector3) { ConstParser = FunctionMValueConstParsers.ParseVector3; ObjectParser = FunctionObjectParsers.ParseVector3; StringParser = FunctionStringParsers.ParseVector3; } else if (IsRgba) { ConstParser = FunctionMValueConstParsers.ParseRgba; ObjectParser = FunctionObjectParsers.ParseRgba; StringParser = FunctionStringParsers.ParseRgba; } else if (IsByteArray) { ConstParser = FunctionMValueConstParsers.ParseByteArray; ObjectParser = FunctionObjectParsers.ParseByteArray; StringParser = FunctionStringParsers.ParseByteArray; } else if (AltShared.Core.IsMValueConvertible(paramType)) { ConstParser = FunctionMValueConstParsers.ParseConvertible; ObjectParser = FunctionObjectParsers.ParseConvertible; StringParser = FunctionStringParsers.ParseConvertible; } else { ConstParser = null; ObjectParser = null; StringParser = null; } }