在泛型(Y)方法中使用泛型(X)委托,其中Y扩展了一些基类。无法转换为基类

时间:2017-08-14 10:49:08

标签: c# class generics constraints

MethodA

Argument 1: cannot convert from 'Callback<T>' to 'Callback<SomeBaseClass>' [Assembly-CSharp] Callback<T> theInstance

中产生错误

Callback<T>

但是MethodD可以很好地将其实例传递给MethodE

当我指定T扩展SomeBaseClass

的约束时,为什么我不能将MethodA中的泛型Callback<SomeBaseClass>实例传递给MethodB中类型{{1}}的参数

2 个答案:

答案 0 :(得分:4)

基本上,你不能这样做,因为它不安全。

假设我们有一个派生自SomeBaseClass的具体类:

public class SomeOtherSpecificClass {}

假设我们将您的MethodB更改为:

void MethodB(Callback<SomeBaseClass> theInstance)
{
    theInstance(new SomeOtherSpecificClass());
}

应该编译,对吗?毕竟,您只是将SomeOtherSpecificClass传递给Callback<SomeBaseClass>,这应该没问题。

然后,如果我这样打MethodA

Callback<SomeSpecificClass> callbcak = data => Console.WriteLine(data.propertyA);
MethodA(callback);

...如果所有这些都被允许,我们会将SomeOtherSpecificClass传递给期望SomeSpecificClass的委托。

您的MethodDMethodE示例很好,因为MethodE只能使用SomeBaseClass的成员...但Callback<SomeSpecificClass>确实要求 SomeSpecificClass,因此您不能将其视为接受SomebaseClass的方法。

更简单地展示:

// This is valid...
string text = "";
object obj = text;

// This isn't...
Action<string> stringAction = text => Console.WriteLine(text.Length);
Action<object> objectAction = stringAction;
// ... because it would allow this:
objectAction(new object());

答案 1 :(得分:3)

不允许这样做,因为您要执行非法分配。如果允许,那意味着你可以作为基类的参数实例传递给方法,实际需要继承类的实例:

Action<TChild> source;
Action<TBase> target;

//your intention:
target = source;
//will be compiled, but as it actual "source", that needs childInstance, not baseInstance,
//it is illegal
target(baseInstance);

您可以尝试修复它或通过逆转来清楚地理解(关键字中):

public delegate void Callback<in T>(T data);

void MethodA(Callback<SomeBaseClass> theInstance)
{
    MethodB(theInstance);
}

void MethodB<T>(Callback<T> theInstance) where T : SomeBaseClass
{
}

法律使用:

Action<TBase> source;
Action<TChild> target;

//your intention:
target = source;
//will work, because it is actual "source", that needs TBase or inherited types like TChild
target(childInstance);