MgS*_*Sam 7 .net c# inheritance covariance
有谁知道为什么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
}
Run Code Online (Sandbox Code Playgroud)
感谢您的回复.
Eri*_*ert 25
首先,返回型逆变没有任何意义; 我想你在谈论返回类型的协方差.
有关详细信息,请参阅此问
您想知道为什么没有实现该功能.phoog是正确的; 该功能未实现,因为此处没有人实现它.一个必要但不充分的要求是该功能的好处超过其成本.
费用相当可观.运行时本身不支持该功能,它直接影响我们使C#版本化的目标,因为它引入了另一种形式的脆弱基类问题,Anders认为它不是一个有趣或有用的功能,如果你真的想要它,你可以通过编写小帮助方法使它工作.(这正是C++的CIL版本所做的.)
好处很小.
高成本,小巧的功能以及简单的解决方法可以非常快速地进行分类.我们有更高的优先事项.
不能输出逆变通用参数,因为在编译时不能保证安全,C#设计者决定不延长对运行时的必要检查.
这是简短的答案,这里稍微长一点......
方差是应用于类型层次结构的转换的属性:
在C#中,"转换"是"用作通用参数".例如,假设一个类Parent
是由类继承的Child
.让我们将这个事实表示为:Parent
> Child
(因为所有Child
实例都是Parent
实例,但不一定是反过来,因此Parent
"更大").我们还说我们有一个通用接口I<T>
:
I<Parent>
> I<Child>
,则T是协变的(原始"方向"在Parent
和之间Child
).I<Parent>
< I<Child>
,则T是逆变的(原始"方向"反转).I<Parent>
与之无关I<Child>
,则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!
Run Code Online (Sandbox Code Playgroud)
...这会在运行时导致问题:a Parent
被实例化并分配给引用Child
.既然Parent
不是Child
,这是错的!
最后一行在编译时看起来很好,因为I<Child>.Get
声明返回Child
,但我们无法在运行时完全"信任"它.C#设计者决定做正确的事情并在编译时完全解决问题,并避免任何运行时检查的需要(与数组不同).
(出于类似但"反向"的原因,协变通用参数不能用作输入.)
Eric Lippert在这个网站上写了一些关于方法覆盖的返回方法协方差的帖子,但我没有看到解决为什么该功能不受支持的问题.但他已经提到,没有计划支持它:https://stackoverflow.com/a/4349584/385844
Eric也喜欢说"为什么不支持X " 的答案总是一样的:因为没有人设计,实现和测试(等等)X . 这方面的一个例子是:https://stackoverflow.com/a/1995706/385844
缺乏这一特征可能有一些哲学原因; 也许埃里克会看到这个问题并启发我们.
编辑
正如Pratik在评论中指出的那样:
interface IBuilder<in T>
{
T Build();
}
Run Code Online (Sandbox Code Playgroud)
应该
interface IBuilder<out T>
{
T Build();
}
Run Code Online (Sandbox Code Playgroud)
这将允许您实施PastryOrder : IBuilder<PastryOrder>
,然后您可以
IBuilder<Order> builder = new PastryOrder();
Run Code Online (Sandbox Code Playgroud)
您可以使用两种或三种方法来解决问题,但是,正如您所指出的,返回方法协方差不是这些方法之一,并且这些信息都没有回答C#不支持它的问题.