重载+操作符,使其对在已检查或未检查的上下文中调用敏感

本文关键字:检查 上下文 调用 操作符 重载 | 更新日期: 2023-09-27 18:04:15

更新:我已经找到了答案,如果没有人这样做,我将在几天内发布。


我正在创建一个数字结构体,所以我重载了算术运算符。下面是一个表示4位无符号整数的结构体的示例:

public struct UInt4
{
    private readonly byte _value;
    private const byte MinValue = 0;
    private const byte MaxValue = 15;
    public UInt4(int value)
    {
        if (value < MinValue || value > MaxValue)
            throw new ArgumentOutOfRangeException("value");
        _value = (byte) value;
    }
    public static UInt4 operator +(UInt4 a, UInt4 b)
    {
        return new UInt4((a._value + b._value) & MaxValue);
    }
}

重载的加法操作符允许如下代码:

var x = new UInt4(10);
var y = new UInt4(11);
var z = x + y;

在这里,计算溢出,因此变量z的值为5。然而,我也希望能够做到这一点:

var x = new UInt4(10);
var y = new UInt4(11);
var z = checked ( x + y );

这个示例应该抛出一个OverflowException。我怎样才能做到呢?

我已经确定,已检查的上下文不会扩展到已调用的方法,因此,例如,无论在已检查或未检查的上下文中调用它,都不会抛出:

public static UInt4 operator +(UInt4 a, UInt4 b)
{
    int i = int.MaxValue;
    //this should throw in a checked context, but when
    //the operator is used in a checked context, this statement
    //is nonetheless unchecked.
    byte b = (byte)i;
    return new UInt4((a._value + b._value) & MaxValue);
}

是否有一种方法可以声明两个加法操作符的重载,一个已检查,另一个未检查?或者,是否有一种方法可以在运行时确定调用者的上下文(这似乎极不可能,但我认为我还是会问),就像这样:

public static UInt4 operator +(UInt4 a, UInt4 b)
{
    byte result = (byte)(a._value + b._value);
    if (result > MaxValue)
        if (ContextIsChecked())
            throw new OverflowException();
        else
            result &= MaxValue;
     return new UInt4(result);
}
private static bool ContextIsChecked()
{
    throw new NotImplementedException("Please help.");
}

重载+操作符,使其对在已检查或未检查的上下文中调用敏感

根据MSDN, checkedunchecked关键字仅适用于整型。因此,您不能创建自己的类型来使用已选中和未选中的关键字。

更新

从c# 11 (. net 7的一部分)开始,用户类型可以定义自定义检查操作符。

public record struct Point(int X, int Y)
{
    public static Point operator checked +(Point left, Point right)
    {
        checked
        {
            return new Point(left.X + right.X, left.Y + right.Y);
        }
    }
    
    public static Point operator +(Point left, Point right)
    {
        return new Point(left.X + right.X, left.Y + right.Y);
    }
}