子类返回类型的C#协方差
有人知道为什么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; _
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
- 如果转换的结果是一组不相关的类型,则转换在
父类
由类子类
继承。让我们将这一事实表示为:Parent
Child
(因为所有Child
实例也都是Parent
实例,但不一定相反,因此Parent
更大)。也可以说我们有一个通用接口I
:
- 如果
I
,则T是协变的(父I
和子
之间的原始“方向”保持不变)
- 如果
I
,则T为逆变型(原始“方向”颠倒)I
- 如果
与I
无关,则T是不变的I
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