为什么'='不能在C#中超载?

时间:2009-03-01 06:23:44

标签: c# operator-overloading

我在想,为什么我不能在C#中重载'='?我能得到更好的解释吗?

12 个答案:

答案 0 :(得分:31)

内存管理语言通常使用引用而不是对象。定义类及其成员时,您正在定义对象行为,但是在创建变量时,您正在处理对这些对象的引用。

现在,operator =应用于引用,而不是对象。当您将引用分配给另一个引用时,实际上将接收引用指向另一个引用的同一对象。

Type var1 = new Type();
Type var2 = new Type();

var2 = var1;

在上面的代码中,在堆上创建了两个对象,一个由var1引用,另一个由var2引用。现在,最后一个语句使var2引用指向var1引用的同一对象。在该行之后,垃圾收集器可以释放第二个对象,并且内存中只有一个对象。在整个过程中,没有任何操作应用于对象本身。

回到为什么=不能重载,系统实现是你可以用引用做的唯一明智的事情。您可以重载应用于对象的操作,但不能重载参考。

答案 1 :(得分:16)

如果你重载了'=',你就永远无法在创建对象引用后更改它。 ...想一想 - 任何对ObjectWithOverloadedOperator的调用=重载运算符内部的某些内容都会导致对重载运算符的另一次调用...那么重载运算符究竟会做什么呢?也许设置一些其他属性 - 或将值设置为新对象(immutability)? 通常不是'='意味着......

然而,您可以覆盖隐含的&显式转换运算符: http://www.blackwasp.co.uk/CSharpConversionOverload.aspx

答案 2 :(得分:8)

因为这样做没有意义。

在C#中指定对变量的对象引用。因此它对变量和对象引用进行操作,而不是对象本身。根据对象类型重载它没有意义。

在C ++中,定义operator =对于可以创建实例的类是有意义的,例如在堆栈上,因为对象本身存储在变量中,而不是对它们的引用。因此,定义如何执行此类分配是有意义的。但即使在C ++中,如果你有一组通常通过指针或引用使用的多态类,你通常会明确禁止通过将operator =和copy构造函数声明为private(或继承自boost :: noncopyable)来复制它们,因为与您在C#中重新定义=的原因完全相同。简单地说,如果你有A类的引用或指针,你真的不知道它是指向A类的实例还是B类的子类。所以你真的知道如何在这种情况下执行=吗?

答案 3 :(得分:6)

实际上,如果您可以定义具有值语义的类并在堆栈中分配这些类的对象,那么重载operator =会有意义。但是,在C#中,你不能。

答案 4 :(得分:4)

一种可能的解释是,如果重载赋值运算符,则无法进行正确的引用更新。它实际上会搞砸语义,因为当人们期望引用更新时,你的=运算符也可能完全做其他事情。不是很友好的程序员。

您可以使用隐式和显式转换运算符来缓解一些无法重载赋值的看似缺点。

答案 5 :(得分:3)

我认为没有任何特别值得注意的理由。一般来说,我认为这个想法是这样的:

  • 如果你的对象是一个庞大而复杂的对象,那么做一些不是=运算符赋值的东西可能会产生误导。

  • 如果你的对象是一个小对象,你也可以使它成为不可变的,并在对它执行操作时返回新的副本,这样赋值运算符的工作方式就像你期望的那样({{1确实。)

答案 6 :(得分:3)

您可以在C#中重载分配。只是不在整个对象上,只对其成员。您使用setter声明了一个属性:

class Complex
{
    public double Real
    {
        get { ... }
        set { /* do something with value */ }
    }

    // more members
}

现在,当您分配到Real时,您自己的代码就会运行。

分配给对象的原因是不可替换的,因为它已经被语言定义为意味着非常重要的东西。

答案 7 :(得分:1)

在C ++中允许使用它,如果不小心,它可能会导致很多混乱和错误搜索。

本文详细解释了这一点。

http://www.relisoft.com/book/lang/project/14value.html

答案 8 :(得分:1)

因为自己在脚下射击是不受欢迎的。

更严重的是,人们只能希望你的意思是比较而不是分配。该框架详细规定了干扰平等/等同性评估,在帮助中或在线与msdn一起寻找“比较”。

答案 9 :(得分:0)

能够为赋值操作定义特殊语义会很有用,但前提是这些语义可以应用于将给定类型的一个存储位置复制到另一个存储位置的所有情况。尽管标准C ++实现了这样的赋值规则,但它还是要求在编译时定义所有类型。当反射和泛型添加到列表中时,事情会变得复杂得多。

目前,.net中的规则指定可以将存储位置设置为其类型的默认值 - 无论该类型是什么 - 通过将所有字节清零。它们进一步指定可以通过复制所有字节将任何存储位置复制到同一类型的另一个存储位置。这些规则适用于所有类型,包括泛型。给定两个类型KeyValuePair<t1,t2>的变量,系统可以将一个变量复制到另一个变量,而不必知道除该类型的大小和对齐要求之外的任何变量。如果t1t2这些类型中任何字段的类型可能实现复制构造函数,则将一个结构实例复制到另一个必须要复杂得多。

这并不是说这种能力提供了一些显着的好处 - 有可能的是,如果设计了一个新框架,自定义价值分配操作员和默认构造函数的好处将超过成本。然而,实施成本在新框架中将是巨大的,并且对于现有框架而言可能是不可克服的。

答案 10 :(得分:0)

此代码对我有用:

public class Class1
{

    ...

    public static implicit operator Class1(Class2 value)
    {
        Class1 result = new Class1();

        result.property = value.prop;

        return result;

    }

}

答案 11 :(得分:0)

重写分配类型

Override Assignment有两种类型:

  1. 如果您觉得用户可能会遗漏某些内容,并且您希望强制用户使用“#cast;” 当你丢失浮动值
  2. 时,就像浮动到整数一样

    int a = (int)5.4f;

    1. 如果您希望用户在没有注意到他/她更改对象类型的情况下执行此操作
    2. float f = 5;

      如何覆盖作业

      对于1,使用explicit关键字:

      public static explicit override ToType(FromType from){
          ToType to = new ToType();
          to.FillFrom(from);
          return to;
      }
      

      对于2,使用implicit关键字:

      public static implicit override ToType(FromType from){
          ToType to = new ToType();
          to.FillFrom(from);
          return to;
      }