public static MemberGetterIndexed <T> DelegateForGetPropertyIndex <T>(this PropertyInfo p) { var idxParams = p.GetIndexParameters(); if (idxParams.Length != 1) { ExThrowers.ThrowArgEx("Property is not index type"); } var parentType = p.DeclaringType; var m = p.GetMethod; var type = p.PropertyType; var idxType = idxParams[0].ParameterType; var genType = typeof(T); if (!genType.IsAssignableFrom(type)) { ExThrowers.ThrowArgEx($"Generic argument ({genType}) cannot be assigned from property type ({type})"); } var instParam = Expression.Parameter(typeof(object), "instance"); var idxParam = Expression.Parameter(typeof(object), "index"); var callInstParam = m.IsStatic ? null : ((parentType == typeof(object)) ? (Expression)instParam : Expression.Convert(instParam, parentType)); var callIdxParam = (idxType == typeof(object)) ? (Expression)idxParam : Expression.Convert(idxParam, idxType); var call = Expression.Call(callInstParam, m, callIdxParam); var body = type.IsValueType ? (Expression)Expression.Convert(call, genType) : call; var expr = Expression.Lambda(typeof(MemberGetterIndexed <T>), body, instParam, idxParam); return((MemberGetterIndexed <T>)expr.Compile()); }
public static ValueTupleGetValuesInvoker ValueTupleValuesGetter(this Type type) { lock (getterLock) { return(getters.GetOrSet(type, () => { if (!type.IsGenericType || !type.Name.StartsWith("ValueTuple`")) { ExThrowers.ThrowArgEx($"{nameof(type)} is not ValueTuple type"); } var fields = type.GetFields(); var instParam = Expression.Parameter(typeof(object), "instance"); var instVT = Expression.Convert(instParam, type); var fieldExpressions = fields.Select((f, i) => { Expression fieldExpr = Expression.Field(instVT, f); if (f.FieldType == typeof(object)) { return fieldExpr; } return Expression.Convert(fieldExpr, typeof(object)); }); var arrayExpr = Expression.NewArrayInit(typeof(object), fieldExpressions.ToArray()); var expr = Expression.Lambda(typeof(ValueTupleGetValuesInvoker), arrayExpr, instParam); return (ValueTupleGetValuesInvoker)expr.Compile(); })); } }
public static MemberGetterIndexed DelegateForGetPropertyIndex(this PropertyInfo p) { var idxParams = p.GetIndexParameters(); if (idxParams.Length != 1) { ExThrowers.ThrowArgEx("Property is not index type"); } var parentType = p.DeclaringType; var m = p.GetMethod; var type = p.PropertyType; var idxType = idxParams[0].ParameterType; var instParam = Expression.Parameter(typeof(object), "instance"); var idxParam = Expression.Parameter(typeof(object), "index"); var callInstParam = m.IsStatic ? null : ((parentType == typeof(object)) ? (Expression)instParam : Expression.Convert(instParam, parentType)); var callIdxParam = (idxType == typeof(object)) ? (Expression)idxParam : Expression.Convert(idxParam, idxType); var call = Expression.Call(callInstParam, m, callIdxParam); var body = type.IsValueType ? (Expression)Expression.Convert(call, typeof(object)) : call; var expr = Expression.Lambda(typeof(MemberGetterIndexed), body, instParam, idxParam); return((MemberGetterIndexed)expr.Compile()); }
public static T CreateCustomDelegate <T>(this MethodInfo m, params Type[] genericArgs) where T : class { var delType = typeof(T); if (!typeof(Delegate).IsAssignableFrom(delType)) { ExThrowers.ThrowArgEx("T is not Delegate type"); } if (genericArgs == null) { ExThrowers.ThrowArgNull(nameof(genericArgs)); } var delInvokeM = delType.GetMethod("Invoke"); var delParams = delInvokeM.GetParameters(); var parentType = m.DeclaringType; var retType = m.ReturnType; var args = m.GetParameters().Select(p => p.ParameterType).ToArray(); if (delParams.Length != (args.Length + (m.IsStatic ? 0 : 1))) { ExThrowers.ThrowArgEx("Number of Delegate arguments does not match method"); } var argsParams = delParams.Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray(); var callParams = m.IsStatic ? argsParams : argsParams.Skip(1); var callArgs = callParams.Select((arg, i) => { if (arg.Type == args[i]) { return((Expression)arg); } return(Expression.Convert(arg, args[i])); }); var callInstParam = m.IsStatic ? null : ((parentType == typeof(object)) ? (Expression)argsParams[0] : Expression.Convert(argsParams[0], parentType)); Expression call = m.IsStatic ? Expression.Call(m.DeclaringType, m.Name, genericArgs, callArgs.ToArray()) : Expression.Call(callInstParam, m.Name, genericArgs, callArgs.ToArray()); if (retType == typeof(void)) { if (delInvokeM.ReturnType != typeof(void)) { call = Expression.Block(call, Expression.Default(delInvokeM.ReturnType)); // Return default(ReturnType) } } else if (retType != delInvokeM.ReturnType) { if (delInvokeM.ReturnType != typeof(void) && (retType.IsValueType || delInvokeM.ReturnType.IsValueType)) { call = Expression.Convert(call, delInvokeM.ReturnType); } } var expr = Expression.Lambda(delType, call, argsParams); return(expr.Compile() as T); }
public static Type AsValueTupleType(this Type[] types) { types.ThrowIfNull(nameof(types)); if (types.Length < 1) { ExThrowers.ThrowArgEx("Unable to create ValueTuple with less than one type"); } if (types.Length > creatorsConstructorCache.Length) { ExThrowers.ThrowArgEx($"Unable to create ValueTuple type with more than {valueTupleTypes.Length} args"); } return(valueTupleTypes[types.Length - 1].MakeGenericType(types)); }
public static ConstructorInvoker AsValueTupleCreator(this Type[] types) { types.ThrowIfNull(nameof(types)); if (types.Length >= creatorsConstructorCache.Length) { ExThrowers.ThrowArgEx($"Unable to create ValueTuple type with more than {creatorsConstructorCache.Length} args"); } return(creators.GetOrAdd(types, t => { var invoker = creatorsConstructorCache[t.Length].MakeGenericMethod(t).DelegateForMethod(); return objs => invoker(null, objs); })); }
public static MethodInvoker DelegateForMethod(this MethodInfo m, params Type[] genericArgs) { if (genericArgs == null) { ExThrowers.ThrowArgNull(nameof(genericArgs)); } var parentType = m.DeclaringType; var retType = m.ReturnType; var args = m.GetParameters().Select(p => p.ParameterType).ToArray(); var instParam = Expression.Parameter(typeof(object), "instance"); var argsParam = Expression.Parameter(typeof(object[]), "args"); var indexedParams = args.Select((arg, i) => { Expression argExpr = Expression.ArrayAccess(argsParam, Expression.Constant(i)); if (arg == typeof(object)) { return(argExpr); } return(Expression.Convert(argExpr, arg)); }).ToArray(); Expression call = m.IsStatic ? Expression.Call(m.DeclaringType, m.Name, genericArgs, indexedParams) : Expression.Call((parentType == typeof(object)) ? (Expression)instParam : Expression.Convert(instParam, parentType), m.Name, genericArgs, indexedParams); Expression <Action <object[]> > callArgEx = a => ExThrowers.ThrowArgEx($"Number of supplied arguments ({a.Length}) does not match number of method arguments ({args.Length})"); var checkerExpr = Expression.IfThen(Expression.NotEqual(Expression.ArrayLength(argsParam), Expression.Constant(args.Length)), Expression.Invoke(callArgEx, argsParam)); var checkedCall = Expression.Block(checkerExpr, call); if (retType == typeof(void)) { call = Expression.Block(checkedCall, Expression.Constant(null, typeof(object))); // Return null } else if (retType.IsValueType) { call = Expression.Convert(checkedCall, typeof(object)); // Box } else { call = checkedCall; } var expr = Expression.Lambda(typeof(MethodInvoker), call, instParam, argsParam); return((MethodInvoker)expr.Compile()); }
public static ConstructorInvoker <T> DelegateForConstructor <T>(this ConstructorInfo c) { var parentType = c.DeclaringType; if (!typeof(T).IsAssignableFrom(parentType)) { ExThrowers.ThrowArgEx($"Can't assign parent type ({parentType}) to T ({typeof(T)})"); } var ctorParams = c.GetParameters().Select(p => p.ParameterType).ToArray(); var argsParam = Expression.Parameter(typeof(object[]), "args"); var indexedParams = ctorParams.Select((arg, i) => { Expression argExpr = Expression.ArrayAccess(argsParam, Expression.Constant(i)); if (arg == typeof(object)) { return(argExpr); } return(Expression.Convert(argExpr, arg)); }).ToArray(); Expression createInst; if (ctorParams.Length > 0) { createInst = Expression.New(c, indexedParams); } else { createInst = Expression.New(c); } Expression <Action <object[]> > callArgEx = a => ExThrowers.ThrowArgEx($"Number of supplied arguments ({a.Length}) does not match number of constructor arguments ({ctorParams.Length})"); var checkerExpr = Expression.IfThen(Expression.NotEqual(Expression.ArrayLength(argsParam), Expression.Constant(ctorParams.Length)), Expression.Invoke(callArgEx, argsParam)); createInst = Expression.Block(checkerExpr, createInst); if (parentType.IsValueType) { createInst = Expression.Convert(createInst, typeof(T)); } var expr = Expression.Lambda(typeof(ConstructorInvoker <T>), createInst, argsParam); return((ConstructorInvoker <T>)expr.Compile()); }
public static MemberGetterIndexed GetMemberGetterDelegate(this Type arrayType) { if (!arrayType.IsArray) { ExThrowers.ThrowArgEx($"{nameof(arrayType)} is not an array"); } var elementType = arrayType.GetElementType(); var instParam = Expression.Parameter(typeof(object), "instance"); var idxParam = Expression.Parameter(typeof(object), "index"); var callInstParam = Expression.Convert(instParam, arrayType); var callIdxParam = Expression.Convert(idxParam, typeof(int)); var arrayIndex = Expression.ArrayIndex(callInstParam, callIdxParam); var body = elementType.IsValueType ? (Expression)Expression.Convert(arrayIndex, typeof(object)) : arrayIndex; var expr = Expression.Lambda(typeof(MemberGetterIndexed), body, instParam, idxParam); return((MemberGetterIndexed)expr.Compile()); }
public static TDelegate CallForType(Type specialised, Type specialisedClass, string specialisedMethodName) { return(creatorCache.GetOrAdd(specialised, _ => { if (!typeof(Delegate).IsAssignableFrom(typeof(TDelegate))) { ExThrowers.ThrowArgEx($"{nameof(TDelegate)} is not a delegate"); } if (!specialisedClass.IsGenericType) { ExThrowers.ThrowArgEx($"{nameof(specialisedClass)} is not a generic type type"); } if (specialisedClass.IsConstructedGenericType) { ExThrowers.ThrowArgEx($"{nameof(specialisedClass)} must be a non-constructed generic type"); } var callArgs = typeof(TDelegate).GetMethod("Invoke").GetParameters().Select(p => p.ParameterType).ToArray(); return specialisedClass.MakeGenericType(specialised).GetMethod(specialisedMethodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static, null, callArgs, null).CreateCustomDelegate <TDelegate>(); })); }
public static Func <object> DelegateForConstructorNoArgs(this ConstructorInfo c) { var parentType = c.DeclaringType; if (c.GetParameters().Length > 0) { ExThrowers.ThrowArgEx("This method is only for constructors with no arguments"); } Expression call = Expression.New(c); if (parentType.IsValueType) { call = Expression.Convert(call, typeof(object)); } var expr = Expression.Lambda(typeof(Func <object>), call); return((Func <object>)expr.Compile()); }
static Type TaskType(Task task) { var genTask = task.GetType(); for (; ;) { if (genTask == typeof(Task)) { ExThrowers.ThrowArgEx("task does not have Result"); } if (genTask.IsGenericType) { var t = genTask.GetGenericTypeDefinition(); if (t == typeof(Task <>)) { break; } } genTask = genTask.BaseType; } return(genTask.GetGenericArguments()[0]); }
public static Func <T> DelegateForConstructorNoArgs <T>(this ConstructorInfo c) { var parentType = c.DeclaringType; if (!typeof(T).IsAssignableFrom(parentType)) { ExThrowers.ThrowArgEx($"Can't assign parent type ({parentType}) to T ({typeof(T)})"); } if (c.GetParameters().Length > 0) { ExThrowers.ThrowArgEx("This method is only for constructors with no arguments"); } Expression call = Expression.New(c); if (parentType.IsValueType) { call = Expression.Convert(call, typeof(T)); } var expr = Expression.Lambda(typeof(Func <T>), call); return((Func <T>)expr.Compile()); }