如何以编程方式创建Func 委托
我有一个小的dependency injection框架,我试图让它动态地解析Lazy
实例。 我的想法是做那样的事情:
DIContainer.Register(); var lazyCommand = DIContainer.Resolve<Lazy>();
前几天我读到Autofac能够做到这一点。
我试图设置该Lazy
实例的构造函数。 在下一个测试代码中,抛出exception,因为所需的类型构造函数需要一个Func
,但我传递的是一个Func
:
static readonly Type _lazyType = typeof(Lazy); static Object ResolveTest(Type type) { if (type.IsGenericType && type.GetGenericTypeDefinition() == _lazyType) { var arg = type.GetGenericArguments()[0]; return Activator.CreateInstance(_lazyType.MakeGenericType(arg), new Func(() => ResolveType(arg))); } else return ResolveType(type); }
我不知道如何创建适合Lazy
构造函数参数的委托。 任何的想法?
干杯。
这不是微不足道的。 一种可能的解决方案是使用reflection:
-
创建一个通用的
ResolveType
方法:public static T ResolveType
() { return (T)ResolveType(typeof(T)); } -
创建使用此方法的委托:
// You probably want to cache this MethodInfo: var method = typeof(TypeContainingResolveType) .GetMethods() .Single(x => x.IsGenericMethod && x.Name == "ResolveType") .MakeGenericMethod(arg); var delegate = Delegate.CreateDelegate( typeof(Func<>).MakeGenericType(arg), method);
-
使用该委托:
return Activator.CreateInstance(_lazyType.MakeGenericType(arg), delegate);
这个应用程序输出“True”和“0”。 即ResolveTest(typeof(Lazy
返回一个Lazy
对象,构造方式与您想要的一样。
using System; using System.Linq.Expressions; namespace TestApp { public class Class1 { public static void Main() { object lazyInt = ResolveTest(typeof(Lazy)); Console.WriteLine(lazyInt.GetType() == typeof(Lazy )); Console.WriteLine(((Lazy )lazyInt).Value); } static readonly Type _lazyType = typeof(Lazy<>); static Object ResolveTest(Type type) { if (type.IsGenericType && type.GetGenericTypeDefinition() == _lazyType) { var arg = type.GetGenericArguments()[0]; var lazyArgType = _lazyType.MakeGenericType(arg); var funcArgType = typeof(Func<>).MakeGenericType(arg); var funcCtor = lazyArgType.GetConstructor(new[] { funcArgType }); Expression> f = () => ResolveTest(arg); var func = typeof(Class1).GetMethod("BuildCastedThing").MakeGenericMethod(arg).Invoke(null, new[] { f }); var arguments = new object[] { func }; var retVal = funcCtor.Invoke(arguments); return retVal; } else return ResolveType(type); } public static object ResolveType(Type type) { return Activator.CreateInstance(type); } public static Func BuildCastedThing (Expression> f) { Expression> expr = Expression.Lambda>( Expression.Convert( Expression.Invoke(f), typeof(T))); return expr.Compile(); } } }
这是一种将ResolveTest
重写为通用Resolve
(例如Resolve
返回Lazy
)。 这有点不同,因为没有等效的ResolveTest(typeof(int))
,它返回一个int
。
static Lazy Resolve () { var arg = typeof(T); return new Lazy (() => (T)ResolveType(arg)); }
或者使用通用的ResolveType
:
static Lazy Resolve () { return new Lazy (() => ResolveType ()); } public static T ResolveType () { return Activator.CreateInstance (); }
public static Object ResolveTest(Type type) { if (type.IsGenericType && type.GetGenericTypeDefinition() == _lazyType) { var arg = type.GetGenericArguments()[0]; Expression> expressionWithFuncOfTypeObject = () => ResolveType(arg); UnaryExpression expressionThatEvaluatesToAnObjectOfTypeArg = Expression.Convert(expressionWithFuncOfTypeObject.Body, arg); LambdaExpression expressionWithFuncOfTypeArg = Expression.Lambda(typeof(Func<>).MakeGenericType(arg), expressionThatEvaluatesToAnObjectOfTypeArg); Delegate funcOfTypeArg = expressionWithFuncOfTypeArg.Compile(); // <-- At runtime this will be of type Func return Activator.CreateInstance(_lazyType.MakeGenericType(arg), funcOfTypeArg); } else return ResolveType(type); }