Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
子类返回类型的C#协方差_C#_.net_Inheritance_Covariance - Fatal编程技术网

子类返回类型的C#协方差

子类返回类型的C#协方差,c#,.net,inheritance,covariance,C#,.net,Inheritance,Covariance,有人知道为什么C#中不支持协变返回类型吗?即使在尝试使用接口时,编译器也会抱怨它是不允许的。请参见下面的示例 class Order { private Guid? _id; private String _productName; private double _price; protected Order(Guid? id, String productName, double price) { _id = id; _

有人知道为什么C#中不支持协变返回类型吗?即使在尝试使用接口时,编译器也会抱怨它是不允许的。请参见下面的示例

class Order
{
    private Guid? _id;
    private String _productName;
    private double _price;

    protected Order(Guid? id, String productName, double price)
    {
        _id = id;
        _productName = productName;
        _price = price;
    }

    protected class Builder : IBuilder<Order>
    {
        public Guid? Id { get; set; }
        public String ProductName { get; set; }
        public double Price { get; set; }

        public virtual Order Build()
        {
            if(Id == null || ProductName == null || Price == null)
                throw new InvalidOperationException("Missing required data!");

            return new Order(Id, ProductName, Price);
        }
    }            
}

class PastryOrder : Order
{
    PastryOrder(Guid? id, String productName, double price, PastryType pastryType) : base(id, productName, price)
    {

    }

    class PastryBuilder : Builder
    {
        public PastryType PastryType {get; set;}

        public override PastryOrder Build()
        {
            if(PastryType == null) throw new InvalidOperationException("Missing data!");
            return new PastryOrder(Id, ProductName, Price, PastryType);
        }
    }
}

interface IBuilder<in T>
{
    T Build();
}

public enum PastryType
{
    Cake,
    Donut,
    Cookie
}
类顺序
{
私有Guid?\u id;
私有字符串“\u productName”;
私人双价;
受保护订单(Guid?id、字符串产品名称、双倍价格)
{
_id=id;
_productName=productName;
_价格=价格;
}
受保护的类生成器:IBuilder
{
公共Guid?Id{get;set;}
公共字符串ProductName{get;set;}
公共双价{get;set;}
公共虚拟秩序构建()
{
如果(Id==null | |产品名称==null | |价格==null)
抛出新的InvalidOperationException(“缺少必需的数据!”);
返回新订单(Id、产品名称、价格);
}
}            
}
类糕点订单:订单
{
PastryOrder(Guid?id,String productName,double price,PastryType PastryType):基本(id,productName,price)
{
}
类PastryBuilder:Builder
{
公共PastryType PastryType{get;set;}
公共覆盖PastryOrder生成()
{
如果(PastryType==null)抛出新的InvalidOperationException(“缺少数据!”);
返回新的PastryOrder(Id、产品名称、价格、PastryType);
}
}
}
接口IBuilder
{
T Build();
}
公共枚举PastryType
{
蛋糕,
甜甜圈,
曲奇
}

感谢您的回复。

Eric Lippert在这个网站上写了几篇关于方法重写的返回方法协方差的文章,但就我所能看到的而言,没有说明为什么不支持该功能。不过,他提到没有支持该计划的计划:

Eric还喜欢说,“为什么不支持X的答案总是一样的:因为没有人设计、实现和测试过(等等)。X。这方面的一个例子如下:

缺少这一特征可能有一些哲学上的原因;也许Eric会看到这个问题并启发我们

编辑

正如普拉蒂克在评论中指出的那样:

interface IBuilder<in T> 
{ 
    T Build(); 
} 
接口IBuilder
{ 
T Build();
} 
应该是

interface IBuilder<out T> 
{ 
    T Build(); 
} 
接口IBuilder
{ 
T Build();
} 
这将允许您实现PastryOrder:IBuilder,然后您可以

IBuilder<Order> builder = new PastryOrder();
IBuilder builder=new PastryOrder();

可能有两到三种方法可以用来解决问题,但是,正如您所注意到的,返回方法协方差不是这些方法中的一种,并且这些信息都不能回答为什么C#不支持它的问题。

更新:这个答案是在2011年写的。二十年来,人们一直在为C#提出回归型协方差,但现在看来,它最终会实现;我相当惊讶。有关公告,请参见的底部;我相信细节会随之而来


首先,返回类型反向变化没有任何意义;我想你说的是返回类型协方差

有关详细信息,请参见此问题:

您想知道为什么没有实现该功能。phoog是正确的;该功能没有实现,因为这里没有人实现过它。一个必要但不充分的要求是该功能的收益超过其成本

费用是相当可观的。运行时不支持该特性,它直接违背了我们使C#版本化的目标,因为它引入了另一种形式的脆弱基类问题,Anders认为它不是一个有趣或有用的特性,如果您真的想要它,您可以通过编写小助手方法使其工作。(这正是C++的CIL版本所做的)。 好处很小


成本高、效益小、解决方法简单的功能很快就被淘汰。我们有更高的优先级。

不能输出逆变泛型参数,因为不能保证在编译时安全,C#设计器决定不延长对运行时的必要检查

这是一个简短的答案,这是一个稍长的答案

什么是方差? 方差是应用于类型层次结构的转换的属性:

  • 如果转换的结果是保持原始类型层次结构“方向”的类型层次结构,则转换为co-variant
  • 如果转换的结果是反转原始“方向”的类型层次结构,则转换是反向的-variant
  • 如果转换的结果是一组不相关的类型,则转换在-variant中为
C#中的方差是多少? 在C#中,“转换”是“用作泛型参数”。例如,假设类
父类
由类
子类
继承。让我们将这一事实表示为:
Parent
Child
(因为所有
Child
实例也都是
Parent
实例,但不一定相反,因此
Parent
更大)。也可以说我们有一个通用接口
I

  • 如果
    I
    I
    ,则T是协变的(父
    和子
    之间的原始“方向”保持不变)
  • 如果
    I
    I
    ,则T为逆变型(原始“方向”颠倒)
  • 如果
    I
    I
    无关,则T是不变的
那么,什么是潜在的不安全? 如果C#编译器真的同意编译以下代码

class Parent {
}

class Child : Parent {
}

interface I<in T> {
    T Get(); // Imagine this actually compiles.
}

class G<T> : I<T> where T : new() {
    public T Get() {
        return new T();
    }
}

// ...

I<Child> g = new G<Parent>(); // OK since T is declared as contravariant, thus "reversing" the type hierarchy, as explained above.
Child child = g.Get(); // Yuck!
类父类{
}
类子:父{
}
接口I{
T Get();//想象一下这实际上是编译的。
}
类别G:I,其中T:new(){
公共部门得不到{
返回新的T();
interface IProvider<T, Coll> where T : ProvidedData where Coll : IEnumerable<T>
{
  Coll GetData();
}

class XProvider : IProvider<X, List<X>>
{
  List<X> GetData() { ... }
}
new XProvider().GetData