【问题标题】:Overloading assignment operator in C#C#中的重载赋值运算符
【发布时间】:2011-05-31 02:00:03
【问题描述】:

我知道= 运算符不能重载,但这里必须有一种方法可以做我想做的事:

我只是创建类来表示定量单位,因为我正在做一些物理学。显然我不能只从原语继承,但我希望我的类的行为与原语完全一样——我只是希望它们的类型不同。

这样我就可以走了,

Velocity ms = 0;
ms = 17.4;
ms += 9.8;

等等

我不知道该怎么做。我想我会像这样写一些类:

class Power
{
    private Double Value { get; set; }

    //operator overloads for +, -, /, *, =, etc
}

但显然我不能重载赋值运算符。有什么办法可以让我得到这种行为?

【问题讨论】:

  • 你看过 F# 的units of measure 功能吗?它知道标准 (ISO) 单位,如 M、KG 和 M/S,它也可以使用单位进行计算。
  • 绝对,我现在正在使用它。它不知道 ISO 单位,而是您自己定义单位,例如 [<Measure>] type m; [<Measure>] type s,然后可以使用 let a = 9.8<m> / 4.3<s> 之类的东西,从而产生 val a : float<m/s> = 2.279069767
  • 对不起,我的意思是说 SI 单位,这些单位是在Microsoft.FSharp.Math.SI 中预定义的。见:blogs.msdn.com/b/andrewkennedy/archive/2008/09/02/…

标签: c# operator-overloading


【解决方案1】:

我认为不能重载,因为C#类都是从Object派生的,所以它们基本上都是对象,而当你使用赋值运算符时,你基本上只是在引用另一个对象。另一方面,如果你使用结构,那么你基本上需要所有的信息,所以当你使用 = 操作符时,所有的字段都会被复制。

所以我想说,面对现实,并实现一个名为 Copy() 的函数,你应该没问题 :-)

【讨论】:

  • 这与其他运营商有何不同?如何将两个对象的所有信息加在一起?我想直接赋值给内部值,而不是覆盖整个对象
  • 我认为它不能被重载,因为语言设计者认为这是一个坏主意。没有技术原因无法完成。
  • 不,我认为是有原因的。假设你有一个对象 a 和一个对象 b。运行语句 a=b 后,a 指向的对象实际上会被垃圾回收(因为不再有对象指向它),那么这里如何实现赋值运算符呢?另一方面,所有其他运算符要么返回另一个对象(例如 a + b),要么在当前对象不会丢失(即垃圾收集)时实际更改当前对象(例如 a += b)。
  • 说,你有一个对象a和一个对象b。运行语句 a=b 后,真正发生的是在 a 上调​​用 ToString 方法,并且该字符串用作 Console.WriteLine 调用的第一个参数,而 b 是第二个参数。这既愚蠢又可怕,但这可能是为= 符号选择的含义。它只是一个恰好在 C# 中具有固定含义的符号。仅供参考,C++ 允许重载该运算符。
  • @Carson:运行时始终可以知道您何时更改引用,因为它必须运行更改它的代码。此外,请仔细查看语言本身。已经有一个设计者认为可以的重载= 的特殊实例:属性设置器。让X 成为foo 的属性。在foo.X = 3 中,= 符号被编译器 替换为调用foo.set_X(3)。您已经可以定义public static T op_Assign(ref T assigned, T assignee) 方法。剩下的就是编译器将= 替换为对它的调用。
【解决方案2】:

您可以创建隐式转换运算符。 page on MSDN 有一个很好的例子。

将它们设为不可变结构也是一个好主意。这正是“原语”的本质,这就是无法从它们继承的原因。您想要一个结构,因为您想要值类型语义,而不是引用类型语义。而且您希望它们不可变,因为可变值类型通常是 bad idea.

【讨论】:

【解决方案3】:

听起来您应该使用 struct 而不是类...然后创建隐式转换运算符,以及用于加法等的各种运算符。

这里有一些示例代码:

public struct Velocity
{
    private readonly double value;

    public Velocity(double value)
    {
        this.value = value;
    }

    public static implicit operator Velocity(double value)
    {
        return new Velocity(value);
    }

    public static Velocity operator +(Velocity first, Velocity second)
    {
        return new Velocity(first.value + second.value);
    }

    public static Velocity operator -(Velocity first, Velocity second)
    {
        return new Velocity(first.value - second.value);
    }

    // TODO: Overload == and !=, implement IEquatable<T>, override
    // Equals(object), GetHashCode and ToStrin
}

class Test
{
    static void Main()
    {
        Velocity ms = 0;
        ms = 17.4;
        // The statement below will perform a conversion of 9.8 to Velocity,
        // then call +(Velocity, Velocity)
        ms += 9.8;
    }
}

(作为旁注......我不明白这如何真正代表速度,因为它肯定需要方向和幅度。)

【讨论】:

  • 完美!谢谢。还有……你是对的。显然,我的物理教授没能把向量狠狠地砸进我的大脑:)
  • 有什么理由不能成为一堂课吗?我希望从 ScalarUnitVectorUnit 类继承,以免为每个单元重复 everything,显然结构不能继承
  • @Henk:不,速度是一个标量,但速度是有方向的。见en.wikipedia.org/wiki/Velocity - “它是一个矢量物理量;定义它需要大小和方向。”
  • @Henk:不。 Velocity 是一个向量,speed 是该向量的大小。
  • @Carson:你可以把它变成一个类,但听起来它更适合作为一个值类型,因为它代表了一个相当原始的“值”而不是一个自然的“对象”。一个类的代码基本上是相同的,所以你可以很容易地对两者进行试验。但是,您将很难在继承树中表达运算符...
猜你喜欢
  • 2013-03-30
  • 2016-08-30
  • 1970-01-01
  • 1970-01-01
  • 2012-04-22
  • 2015-06-01
  • 2011-01-27
  • 2012-08-17
  • 2018-12-27
相关资源
最近更新 更多