我必须定义每一个运算符吗

本文关键字:运算符 每一个 定义 | 更新日期: 2023-09-27 18:20:39

假设我有一个只有一个字段的结构:

public struct Angle
{
    public static readonly double RadiansPerDegree = Math.PI / 180;
    private readonly double _degrees;
    public Angle(double degrees)
    {
        _degrees = degrees;
    }
    public double Degrees
    {
        get { return _degrees; }
    }
    public double Radians
    {
        get { return _degrees * RadiansPerDegree; }
    }
    public static Angle FromDegrees(double value)
    {
        return new Angle(value);
    }
    public static Angle FromRadians(double value)
    {
        return new Angle(value / RadiansPerDegree);
    }
}

这很有效,直到我想做这样的事情:

var alpha = Angle.FromDegrees(90);
var beta = Angle.FromDegrees(100);
var inequality = alpha > beta;
var sum = alpha + beta;
var negation = -alpha;
//etc.

因此,我实现了IEquatable<in T>IComparable<in T>,但这仍然没有启用任何运算符(甚至没有启用==<>=等)

所以,我开始提供运营商过载。

例如:

public static Angle operator +(Angle a, Angle b)
{
    return new Angle(a._degrees + b._degrees);
}
public static Angle operator -(Angle a)
{
    return new Angle(-a._degrees);
}
public static bool operator >(Angle a, Angle b)
{
    return a._degrees > b._degrees;
}

然而,当我看到所有我可以想象的过载(+, -, !, ~, ++, --, true, false, +, -, *, /, %, &, |, ^, <<, >>, ==, !=, <, >, <=, >=)的运算符时,我开始觉得一定有更好的方法。毕竟,结构体只包含一个字段,而该字段是一个值类型。

有没有办法让double的所有操作员都能一次完成?还是我真的必须把我可能想用手支持的每一个操作员都打出来?

(即使我有两个或三个字段,我仍然希望能够在一个批次中添加运算符…)

我必须定义每一个运算符吗

重载运算符的目的是定义如何使用这些运算符添加和操作自定义类型的对象,因此,如果您的第二个字段是字符串数组,您希望如何自动实现++运算符?没有合理的答案,特别是因为我们不知道对象的上下文或它的用法,所以答案是是的,你必须自己重载运算符

对于记录,如果你真的只需要一个字段,而且它只是一个双字段,那么首先不要使用结构,除非你需要重载运算符来执行默认情况下以外的其他操作——这显然是过度工程的情况!

是的,必须定义要使用的每个运算符。编译器无法知道您希望每个运算符做什么,除了互为否定的运算符之外(即使这些运算符也不一定是显而易见的;如果您想模仿标准SQL null行为,==!=在与null相比时都会返回false,该怎么办?)。

在大多数情况下,我同意LaceSnr的观点:它不适用于任何返回新对象的运算符(例如+,*ect.)。对于比较器,它可以工作(就像在中一样,可能有一个注释说"在所有比较器操作中使用此方法的返回值来代替此对象"),但我不知道有什么类似的情况。

我不确定C#中注释的限制是什么,但可能会创建一个这样做的注释(对于返回bool的运算符),但除非您计划非常使用它,否则我怀疑它是否值得您花费时间。

话虽如此,如果有一个对象在构造函数中只带了一个参数,而这个参数是方法的返回值,那么也应该可以这样做。

当然,要做到这一切都需要一些非常极端的类修补,我真的不适合就…

给出建议