无法转换Func <t1,t2 <u =“”>&gt;到Func <t1,t2 <v =“”>&gt;与V:U </t1,> </t1,>

时间:2015-02-05 15:47:34

标签: c# .net-3.5 covariance

我有一个返回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);
    }
}

1 个答案:

答案 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的新实例。