繁体   English   中英

为什么不能将运算符或转换方法声明为虚拟的? C#

[英]Why isn't It possible to declare operator or conversion methods virtual ? C#

如果您能确切地告诉我为什么我们不能在基础 class 中声明操作符方法是虚拟的,我将不胜感激,这样我们就可以在派生类中覆盖它们。

在互联网上搜索后,我找不到可靠的答案。

对于二元运算符,重写对编译器没有意义是合乎逻辑的,但是像++一元运算符呢?

为什么不能告诉编译器根据引用变量指向的 object 类型来调用不同的二元运算符方法?

如果这个问题太理论化并且缺乏实用性,我深表歉意。

根据Eric Lippert 的这篇文章,有一些原因:

  • 它有助于避免破坏运算符对称性:

如果你定义一个运算符+,它接受一个 C 和一个 int,那么 c+2 是合法的,但 2+c 不是,这严重破坏了我们对加法运算符应该如何表现的直觉。

  • C# 也区分了值和引用,但如果实例运算符重载只能在不可为空的值类型上定义,那就很奇怪了,如果 c+2 可以抛出 null 引用异常也会很奇怪。

和:

这些和其他困难,以及从 static 机制构建您自己的单(或双)虚拟调度机制的难易程度。 可以轻松决定不向 C# 添加实例或虚拟运算符重载

让我们看这个简单的例子:

void Main()
{
    var booking1 = new Booking() { Name = "Elon", Pax = 2 }; //romatic dinner
    var booking2 = booking1 + 2; // two friends are coming :-(
    var booking3 = -3 + booking2; // everyone else bailed.
}

public class Booking
{
    public string Name { get; init; }
    public int Pax { get; init; }
    
    public static Booking operator +(Booking booking, int paxDelta) =>
        new Booking() { Name = booking.Name, Pax = booking.Pax + paxDelta };
    
    public static Booking operator +(int paxDelta, Booking booking) =>
        booking + paxDelta;
}

这允许我创建一个预订,然后通过Booking + intint + Booking更改人数。

现在,如果我们更改为假设的实例方法,这就是我们得到的:

public Booking operator +(int paxDelta) =>
    new Booking() { Name = this.Name, Pax = this.Pax + paxDelta };

// Can't implement!
//public Booking +(Booking booking) => booking + ????;

这意味着我只能输入Booking + int ,而不是相反。

解决这个问题的方法很简单。 只需这样做:

public class Booking
{
    public string Name { get; init; }
    public int Pax { get; init; }

    protected virtual Booking AddInternal(int paxDelta) =>
        new Booking() { Name = this.Name, Pax = this.Pax + paxDelta };

    public static Booking operator +(Booking booking, int paxDelta) =>
        booking.AddInternal(paxDelta);

    public static Booking operator +(int paxDelta, Booking booking) =>
        booking + paxDelta;
}

public class SubBooking : Booking
{
    protected override Booking AddInternal(int paxDelta)
    {
        var booking = base.AddInternal(paxDelta);
        return new SubBooking()
        {
            Name = $"{this.Name}!",
            Pax = this.Pax
        };
    }
}

现在我有对称性并且我有可覆盖性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM