泛型的两种用法有什么区别(协变)

What is the difference between the two uses of generics (covariance)

我想我明白泛型不支持协变,这就是为什么第一个示例不起作用并给出 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);

第一个例子与协方差无关。您只是混淆了 T 的真正含义; TSomeType,不是 MyClass

在第二个示例中,您让编译器正确推断类型,这就是它起作用的原因。

编辑

修改你的问题并没有解决问题,你还在混淆 T 是什么:在 MyClassTSomeType。在 SendingEmail<T> T 应该是 SomeType 因为 abcIGenericType<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> 执行相同的操作; IEnumerableT 中是协变的,而 IListT 中是不变的。

请注意,C# 确实破坏了数组中的协变性,以下是合法的:Animal[] animals = new Tiger[3]。它坏了,因为现在你可以合法地做 animals[0] = new Turtle(); 并且......哎哟......你只是遇到了一个运行时异常。这种场景正是IListT中不变的原因。为什么 C# 破坏了数组中的协变性?我不知道,但我认为这是一个不幸的(尽管可能是合理的)设计决定。