我有一个返回Func<ConstructorInfo, MyDelegate<T>>
的方法,其中MyDelegate
是一个通用(协变)委托。现在我想将此方法的结果分配给Func<ConstructorInfo, MyDelegate<U>>
类型的变量,其中U
是来自T
(T:U)的基类。但我得到InvalidCastException
。这是因为Func
不是协变的(至少在.NET 3.5中)或者我该如何解决这个问题?
编辑一些代码:
using System;
using System.Reflection;
using System.Linq.Expressions;
public delegate T MyDelegate<out T>(params object[] args);
class GenericTypeFactory
{
public static MyDelegate<T> GetActivator<T>(ConstructorInfo ctor)
{
// make a NewExpression that calls the ctor with the args we
// just created
var newExp = Expression.New(ctor);
var lambda = Expression.Lambda(typeof(MyDelegate<T>), newExp);
var compiledExpression = (MyDelegate<T>)lambda.Compile();
return compiledExpression;
}
}
在我的大班上:
using System;
using System.Reflection;
using System.Linq.Expressions;
class MyClass {
private Func<ConstructorInfo, MyDelegate<T>> createLambdaExpression<T>()
{
// this Func is only introduced to ensure name-safety when
// refactoring the GenericTypeFactor.GetActivator-method
// (changing params, other name, ...) we could also use
// Reflection to get this method by its name the generic-type
// argument <T> is only a placeholder
Func<ConstructorInfo, Delegate> myFunc =
GenericTypeFactory.GetActivator<T>;
MethodInfo method = myFunc.Method;
// set the params for the method we obtained above
var paramExp = Expression.Parameter(typeof(ConstructorInfo), "ctor");
// call the method with its params
var call = Expression.Call(method, paramExp);
return Expression.Lambda<Func<ConstructorInfo, MyDelegate<T>>>(
call,
paramExp)
.Compile();
}
void DoSomeThing<T>()
{
Type customType = typeof(T); // not really, but for simplicity
// type T is only a dummy-type (replaced in next line)
Func<Delegate> myFunc = this.createLambdaExpression<T>;
MethodInfo method =
myFunc.Method.GetGenericMethodDefinition()
.MakeGenericMethod(customType);
var getActivator = (Func<ConstructorInfo, MyDelegate<T>>)
method.Invoke(this, null);
}
}
答案 0 :(得分:0)
我仍然不确定为什么它不像我上面发布的那样工作。现在我找到了另一种方式,至少有效(尽管它不是我最喜欢的)。为此我只是将createLambdaExpression方法的结果转换为Delegate而不是具体的Func并调用其DynamicInvoke方法。这当然不是考虑到性能的最佳选择,但是当我缓存所有激活器时,我只需要调用一次而不是总是我需要一个特定类型的新实例。
Func<Delegate> myFunc = this.createLambdaExpression<T>;
MethodInfo method = myFunc.Method.GetGenericMethodDefinition().MakeGenericMethod(customType);
var getActivator = (Delegate)method.Invoke(this, null);
var activator = (Delegate)getActivator.DynamicInvoke(new[] { ctor });
最后,我调用((ObjectActivator<T>) activator)()
,它将返回一个类型为customType的新实例。