C# 方法C的泛型抽象参数#

C# 方法C的泛型抽象参数#,c#,.net,C#,.net,我有这个代码示例。我不明白为什么它不能编译。它不允许从D转换为A D继承AC继承B,这意味着我应该能够将D传递到a方法参数中,对吗?我可能错过了一些明显的东西 using System.Collections.Generic; public class Program { public void Main() { var d = new D(); Foo(d); //Cannot convert D to A<B> }

我有这个代码示例。我不明白为什么它不能编译。它不允许从
D
转换为
A

D
继承
A
C
继承
B
,这意味着我应该能够将
D
传递到
a
方法参数中,对吗?我可能错过了一些明显的东西

using System.Collections.Generic;

public class Program
{
    public void Main()
    {
        var d = new D();
        Foo(d);  //Cannot convert D to A<B>

    }

    private void Foo(A<B> bar)
    {

    }   
}

public abstract class A<TypeB> where TypeB : B
{
     public abstract List<TypeB> list { get; set; } 
}

public abstract class B
{
}

public class C : B
{

}

public class D : A<C>
{
     public override List<C> list { get; set; }
}
使用System.Collections.Generic;
公共课程
{
公共图书馆
{
var d=新的d();
Foo(d);//无法将d转换为
}
私人酒吧
{
}   
}
公共抽象类A,其中类型B:B
{
公共摘要列表{get;set;}
}
B类公开摘要
{
}
公共类C:B
{
}
D级:A
{
公共覆盖列表{get;set;}
}

这个问题在这个网站上被问了数百次

假设你有一碗水果。是一碗苹果吗?苹果是水果,为什么一碗水果不是一碗苹果呢?显然,因为一碗水果可能已经含有香蕉,所以不是一碗苹果

假设你有一碗苹果。是一碗水果吗?你想说“苹果是水果,所以一碗苹果就是一碗水果”。但这是错误的一碗水果是可以放香蕉进去的东西,因为有一种操作可以在一碗水果上执行,而不能在一碗苹果上执行,所以一碗苹果不能用于预期一碗水果的环境中

所需转换类型的技术名称为“通用协变转换”。C#仅在少数特定情况下支持通用协变转换:

  • “外部”类型必须是接口或委托,例如,
    IEnumerable
  • “内部”类型必须是引用类型,如字符串,而不是值类型,如int
  • “外部”类型必须标记为协方差安全;这是由编译器检查的
您可以在需要
IEnumerable
的上下文中使用
IEnumerable
,因为无法将香蕉放入
IEnumerable
中。但是您不能将类
A
用作
A
,因为编译器不相信您已经阻止了在只能接受苹果的方法中使用另一种类型的香蕉来扩展水果的可能性


在这个网站上搜索“协方差和逆变”,你会发现很多关于这方面的问题。

因为
D
不是从
a
继承的。如果你能写
A ab=newd()那么这个代码可以工作,但你不能这样做。谢谢Eric。答案很清楚。看来我确实错过了一些显而易见的东西。@FreekvanZee:我不会说这是显而易见的。这是一个非常常见的问题;如果很明显为什么它不起作用,就不会经常被问到。此外,许多人对逆变非常不了解。也就是说:我有一个
IComparer
可以比较任何两种动物,所以我可以用它作为
IComparer
来比较两只老虎。请注意,与
IEnumerabl
IEnumerable
相比,可兑换方向是向后的,因此是反向的。