我认为我理解泛型不支持协方差,这就是为什么第一个例子不起作用并给出Invalid Cast异常的原因。但是一切都在编译。
但为什么第二个例子有效呢?我只能看到它是同一件事。
MyClass 是这样的:
public interface IGenericClass<T> { }
public class MyClass : IGenericClass<SomeType>
{
}
不工作:
public class SendingEmail<T>
{
IGenericClass<T> abc;
public void Send(IGenericClass<T> _abc)
{
this.abc = _abc;
}
}
用法:
var myClass = new MyClass();
SendingEmail<MyClass> sendingEmail = new SendingEmail<MyClass>();
sendingEmail.Send(IGenericClass<MyClass>myClass);
//sendingEmail.Send(myClass); This was wrong
也尝试过:
删除,因为它从未编译
工作:
class SendingEmail
{
void Send<T>(MyGenericClass<T> abc)
{
}
}
用法:
SendingEmail sendingEmail = new SendingEmail();
sendingEmail.Send(myclass);
答案 0 :(得分:2)
第一个例子与协方差无关。你很容易混淆T
的真实含义; T
为SomeType
,而非MyClass
。
在第二个例子中,你让编译器正确推断出类型,这就是它的工作原理。
修改强>
对您的问题的修改无法解决问题,您仍然会混淆T
的内容:MyClass
T
中的SomeType
是SendingEmail<T>
。在T
SomeType
还应该abc
,因为IGenericType<T>
已键入IGenericType<SomeType>
,您最终希望它为SendingEMail<MyClass>
}。
在您的代码中,您创建了一个类型为abc
的实例,这意味着IGenericType<MyClass>
实际上是IGenericType<SomeType>
,这是错误的;您无法将IGenericType<IGenericType<SomeClass>>
转换为sendingEMail(MyClass)
,而这正是您在致电var sendingEmail = new SendingEmail<SomeType>()
时所做的事情;
您需要做的是:IEnumerable<Animal> animals = Enumerable.Emtpy<Tiger>()
。
关于这与类型方差有关,事实并非如此。例如,类型差异允许您执行IList<T>
,不允许您对IEnumerable
执行相同操作; T
中的IList
是协变的,而T
中的Animal[] animals = new Tiger[3]
是不变的。
请注意,C#确实在数组中破坏了协方差,以下是合法的:animals[0] = new Turtle();
。它已经坏了,因为现在你可以合法地做IList
并且......哎......你刚刚得到一个运行时异常。这种情况正是T
中AppContext
不变的原因。为什么C#在数组中破坏了协方差?我不知道,但我认为这是一个不幸(虽然可能是合理的)设计决定。