用户定义的类型可重载预定义的 C# 运算符。也就是说,当一个或两个操作数都是某类型时,此类型可提供操作的自定义实现。“可重载运算符”部分介绍了哪些 C# 运算符可重载。

使用 operator 关键字来声明运算符。运算符声明必须符合以下规则:

  • 同时包含 public 和 static 修饰符
  • 一元运算符有一个输入参数。二元运算符有两个输入参数。在每种情况下,都至少有一个参数必须具有类型 T 或 T?,其中 T 是包含运算符声明的类型;T? 表明允许该类型为 null 值。

下面的示例定义了一个表示分数的简单结构。该结构会重载一些算术运算符:

static void Main(string[] args)
    {
        JG分数 a = new ( 5 , 4 );
        JG分数 b = new ( 1 , 2 );
        Console . WriteLine ( $"-a = {-a}" );
        Console . WriteLine ( $"a + b = {a + b}" );
        Console . WriteLine ( $"a - b = {a - b}" );
        Console . WriteLine ( $"a × b = {a * b}" );
        Console . WriteLine ( $"a ÷ b = {a / b}" );
   }

public readonly struct JG分数
    {
        private readonly int Zi , Mu;
        public JG分数 ( int 分子 , int 分母 )
            {
                if ( 分母 == 0 )
                    {
                        throw new ArgumentException ( "分母不能是 0。" , nameof ( 分母 ) );
                    }
                Zi = 分子;
                Mu = 分母;
            }

    public static JG分数 operator + ( JG分数 自身 ) => 自身;
    public static JG分数 operator - ( JG分数 自身 ) => new ( -(自身 . Zi) , 自身 . Mu );
    public static JG分数 operator + ( JG分数 加数1 , JG分数 加数2 ) => new ( 加数1 . Zi * 加数2 . Mu + 加数2 . Zi * 加数1 . Mu , 加数1 . Mu * 加数2 . Mu );
    public static JG分数 operator + ( JG分数 加数1 , int 加数2 ) => new ( 加数1 . Zi + 加数2 * 加数1 . Mu , 加数1 . Mu );
    public static JG分数 operator - ( JG分数 被减数 , JG分数 减数 ) => 被减数 + ( -减数 );
    public static JG分数 operator * ( JG分数 乘数1 , JG分数 乘数2 ) => new ( 乘数1 . Zi * 乘数2 . Zi , 乘数1 . Mu * 乘数2 . Mu );
    public static JG分数 operator / ( JG分数 被除数 , JG分数 除数 )
        {
            if ( 除数 . Zi == 0 )
                throw new DivideByZeroException ( "除数不能为 0。" );
                return new ( 被除数 . Zi * 除数 . Mu , 被除数 . Mu * 除数 . Zi );
        }

    public override string ToString ( )
        {
            JG分数 f = FF约分 ( this );
            return $"{f . Zi} / {f . Mu} = {( double ) f . Zi / ( double ) f . Mu}";
        }

    private JG分数 FF约分 ( JG分数 分数 )
        {
            int 分子 = 分数 . Zi;
            int 分母 = 分数 . Mu;
            BigInteger zi = new ( 分子 ) , mu = new ( 分母 );
            BigInteger gys = BigInteger . GreatestCommonDivisor (mu, zi );
            zi /= gys;
            mu /= gys;
            return new ( ( int ) zi , ( int ) mu );
        }
    }

可以通过定义从 int 到 JG分数 的隐式转换来扩展前面的示例。然后,重载运算符将支持这两种类型的参数。也就是说,可以将一个整数添加到一个分数中,得到一个分数结果。

上例来自 MSDN,我多写了一个关于分数加整数和约分的过程。约分的过程中,使用了 BigInteger 的求最大公约数的过程(GreatestCommonDivisor),以便约分分数。

还可以使用 operator 关键字来定义自定义类型转换。

可重载运算符

运算符说明
+x, -x, !x, ~x, ++, --, true, falsetrue 和 false 必须成对重载
x + y, x - y, x * y, x / y, x % y, x & y, x or y, x ^ y, x << y, x >> y, x >>> y
x == y, x != y, x < y, x > y, x <= y, x >= y== 和 !=、< 和 >、<= 和 >= 必须成对重载

备注: 第二行中的 x or y 实际是 x | y。

不可重载运算符

运算符备选方法
x && y,x 短路or y重载 true 和 false 运算符以及 & 或 or 运算符
a[i],a?[i]定义索引器
(T)x定义可由强制转换表达式执行的自定义类型转换
+=,-=,*=,/=,%=,&=,or=,^=,<<=,>>=,>>>=重载相应的二元运算符。例如,重载二元 + 运算符时,会隐式重载 +=
^x,x = y,x.y,x?.y,c ? t : f,x ?? y,??= y,x..y,x->y,=>,f(x),as,await,checked,unchecked,default,delegate,is,nameof,new,sizeof,stackalloc,switch,typeof,with

备注: 第一行中的“短路or”实际为“||”,“or”实际为“|”。


兔子码农
4 声望1 粉丝

一个酒晕子


« 上一篇
C# 的 new