【问题标题】:Default arithmetic operators in C#C# 中的默认算术运算符
【发布时间】:2016-12-11 07:20:09
【问题描述】:

c# 如何为没有重载运算符的类定义 +、-、*、/ 运算符?我已经实现了以下课程。在不重载任何操作符的情况下,上述操作符可以正常工作,并且按照我要实现的方式工作! 代码如下:

class Number
{
    private float mDecimal;
    public float Decimal
    {
        get { return mDecimal; }
    }

    private int mOrder;
    public int Order
    {
        get { return mOrder; }
    }

    public Number(float dec, int pow)
    {
        mDecimal = dec;
        mOrder = pow;
    }

    public Number Power(Number number)
    {
        throw new NotImplementedException();
    }

    public static implicit operator Number(float num)
    {
        int pow = 0;
        while (num > 1000)
        {
            num *= 0.1f;
            ++pow;
        }

        return new Number(num, pow);
    }

    public static implicit operator float(Number num)
    {
        float result = num.mDecimal;
        for (int i = 0; i < num.mOrder; ++i)
            result *= 10;
        return result;
    }
}

现在考虑这段使用代码:

Number n1 = 5;
Number n2 = 10;
Number n3 = n1 + n2;

n3 计算结果为 15!其他运营商也会出现这种情况!

【问题讨论】:

  • 这是因为您已经定义了implicit operator float - 所以+ 运算符会将您的值从Number 隐式转换为float (System.Single),执行加法,然后转换返回。
  • 你没有尝试在隐式运算符中放置一个断点,这是唯一可行的原因吗?
  • @Andrew 我是 C# 新手。我的背景是 C++,它不能隐式地处理这些情况。所以在不知道类型的情况下,由于 Number 可以转换为浮点数,所以它使用浮点数?我为另一个自定义类放置了其他转换运算符,但它再次使用了浮点运算符。编译器如何选择进行哪种转换来提供算术运算符?

标签: c#


【解决方案1】:

n3 = n1 + n2 的评估如下:

  1. 首先,确定候选运算符列表,包括任何用户定义的重载 (ECMA-334, section 14.2.4)。不适用,因此候选运算符集成为预定义的二元运算符+。如果您定义了自己的operator+(Number, Number),这就是它被选中的地方。 (您可能确实希望实现它以防止来回转换产生舍入错误。)
  2. 现在重载决议开始确定应该使用+ 的哪个实现(第14.4.2 节)。这可能是 C# 规范中最复杂的部分,但我们不需要深入研究它——我们只需要知道在选择适当的重载 (14.4.2.1) 时会应用隐式转换。对于精确的规则,您还需要阅读关于用户定义转换的第 13.4 节。
  3. 该语言使用内置转换平等地对待用户定义的隐式转换。在这种情况下,由于存在从 Numberfloat 的隐式转换,因此解析后剩下的唯一候选 + 重载是具有隐式转换的 float operator +(float, float),因此会调用它。
  4. 生成的float 然后通过使用其他运算符隐式转换为Number。请注意,即使没有这个,您仍然会得到一个 float 加法,结果只是不会转换回来。编译器实际上并没有“提升”运算符,尽管效果大致相同(提升确实发生在值类型的可为空版本,但这是另一回事)。

当混合具有隐式转换的类型时,事情会变得很棘手。重载解析非常努力地做正确的事情,并且规则是明确的,但即使如此,也很难看到何时涉及转换,因此不要过度使用隐式转换运算符。显式转换需要更多的击键,但也更容易判断最终将调用哪个运算符。这在您最初开发类型时肯定是正确的,因此您可以检查哪些运算符尚未实现(但出于性能或精度原因需要)。

【讨论】:

  • 这正是人们可以从不止一种方式中受益的答案类型。
猜你喜欢
  • 2012-10-10
  • 2013-08-09
  • 1970-01-01
  • 1970-01-01
  • 2020-03-10
  • 2021-05-11
  • 2014-09-12
  • 1970-01-01
相关资源
最近更新 更多