PI常见的设计问题是在覆盖方法时无法使用更特定的返回类型。 一个典型的克隆方法就是一个很好的例子。
public abstract Request Clone();
在子类中,您可能希望像这样实现它:
public override FtpRequest Clone() { ... }
由于FtpRequest是Request的子类,因此从逻辑上讲这很有意义。 但是您实际上不能在.NET中执行此操作,因为重写必须完全匹配。 您也不能拥有仅根据返回类型而有所不同的替代和新方法。 因此,通常您会遇到一些复杂的事情,例如:
public Request Clone() => OnClone(); protected abstract Request OnClone();
然后在子类中:
public new FtpRequest Clone() => (FtpRequest)OnClone(); protected override Request
(建议49),协变返回类型 中探讨了更改重写方法的返回类型的建议。
当最初在2017年提出该功能时,将使用一些“编译器魔术”实现该功能。 截至2019年10月,重点已转移到使它成为CLR的一项功能。
覆盖方法必须具有可通过标识或隐式引用转换转换为重写基方法的返回类型的返回类型。
当前规则是:
覆盖方法和覆盖的基本方法具有相同的返回类型。
属性和索引器
属性和索引器包含在此功能中,但前提是它们是只读的。 对协变属性和索引设置器将没有匹配的支持。
接口
接口上的方法可以使用与子类/基类相同的规则覆盖基本接口上的协变方法。
当类实现接口时,实现方法可以与接口方法协变。
为了进行接口映射,在以下情况下,类成员A与接口成员B匹配:
A和B是方法,并且A和B的名称和形式参数列表相同,并且A的返回类型可以通过对B的返回类型进行隐式引用转换的标识转换为B的返回类型。
对于隐式实现的接口,此规则更改可能会导致重大更改。 这将在异常情况下发生,在这种情况下,子类重新实现了基类已经实现的接口。
interface I1 { object M(); } class C1 : I1 { public object M() { return "C1.M"; } } class C2 : C1, I1 { public new string M() { return "C2.M"; } }
安迪·高克(Andy Gocke)对规则进行了一些修改,以避免出现重大变化:
如果没有其他实现(包括默认实现),我们是否可以更改对映射成员的搜索,以考虑具有不同协变量返回的隐式实现?
不幸的是,这与接口上的默认实现不兼容。 Neal Gafter写道:
我看不到在二进制兼容性方案中如何工作。 如果使用默认实现发布了新版本的接口,则运行时将更改为使用该接口,而不是基类的实现?
Microsoft正在内部跟踪对协变返回类型必要的运行时支持的优先级。
出处:
https://www.infoq.com/news/2020/01/CSharp-Covariant-Return-Types/
翻译:来自google翻译
版权声明:本文来源于网络收集或网友供稿,仅供学习交流之用,如有侵权,请留言转告小编立即删除。
- EOF -
技术群:添加小编微信dotnet999
公众号:dotnet讲堂