无法使用 V 将 Func<T1, T2<U>> 转换为 Func<T1, T2<V>> : U
cannot cast Func<T1, T2<U>> to Func<T1, T2<V>> with V : U
我有一个返回 Func<ConstructorInfo, MyDelegate<T>>
的方法,其中 MyDelegate
是一个通用(协变)委托。现在我想将此方法的结果分配给 Func<ConstructorInfo, MyDelegate<U>>
类型的变量,其中 U
是 T
(T : U) 的基数 class。但是我得到 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;
}
}
而在我的主-class:
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);
}
}
我仍然不确定为什么它没有像我上面发布的那样工作。现在我找到了另一种方法,至少有效(虽然它不是我最喜欢的)。为此,我只是将我的 createLambdaExpression 方法的结果投射到委托而不是具体的 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)()
,这将 return 一个 customType 类型的新实例。
我有一个返回 Func<ConstructorInfo, MyDelegate<T>>
的方法,其中 MyDelegate
是一个通用(协变)委托。现在我想将此方法的结果分配给 Func<ConstructorInfo, MyDelegate<U>>
类型的变量,其中 U
是 T
(T : U) 的基数 class。但是我得到 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;
}
}
而在我的主-class:
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);
}
}
我仍然不确定为什么它没有像我上面发布的那样工作。现在我找到了另一种方法,至少有效(虽然它不是我最喜欢的)。为此,我只是将我的 createLambdaExpression 方法的结果投射到委托而不是具体的 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)()
,这将 return 一个 customType 类型的新实例。