如果“== 运算符未定义”会发生什么?

发布于 2024-08-25 12:09:03 字数 348 浏览 6 评论 0原文

如果“== 运算符未定义”会发生什么?

示例:

class a
{
    int variable = 0;
}
class b
{
    void proc()
    {
        a ref1 = new a();
        a ref2 = new a();
        bool cmp1 = ref1 == ref2;//?
        bool cmp2 = ref1 == ref1;//?
    }
}

使用结构时有什么不同吗?

封送 (System.Runtime.Remoting.*) 对象(单例)怎么样?

What happens if "== operator is not defined"?

Example:

class a
{
    int variable = 0;
}
class b
{
    void proc()
    {
        a ref1 = new a();
        a ref2 = new a();
        bool cmp1 = ref1 == ref2;//?
        bool cmp2 = ref1 == ref1;//?
    }
}

Does it differ when working with structs?

How about marshaled (System.Runtime.Remoting.*) objects (singletons)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

猥︴琐丶欲为 2024-09-01 12:09:03

对于用户定义的值类型,您的代码将无法编译。

具体来说,它会因以下错误而编译失败:“运算符 '==' 无法应用于类型 'a' 和 'a' 的操作数”。

"== 和 != 运算符无法对结构进行操作,除非该结构显式重载它们。"

您必须重载两者。您很可能不想在您的方法中使用默认的 Equals(),因为
“...对于结构,Object.Equals(Object)(这是 System.ValueType 中的重写版本)的默认实现通过使用反射来比较类型中每个字段的值来执行值相等检查。当实现者重写结构中的虚拟 Equals 方法时,目的是提供一种更有效的方法来执行值相等检查,并可选择将比较基于结构的字段或属性的某些子集。”

对于用户定义的引用类型(简化的情况,如OP的示例):

“即使类没有重载 == 和 != 运算符,但默认行为是在类中执行引用相等性检查。应该重载 == 和 != 运算符,但这不是必需的。”

如果不重载运算符,则很可能只有引用相等测试。

“简化的情况”,因为运算符重载解析可能会选择其他实现而不是默认

//Minimal example, for demonstration only.
//No Equals(), GetHaschode() overload, no IEquatable<T>, null checks, etc..
class Program
{
    static void Main()
    {

        MyMoreDerived a = new MyMoreDerived() { fbase = 1, fderived = 3 };
        MyMoreDerived b = new MyMoreDerived() { fbase = 2, fderived = 3 };

        //Even though MyMoreDerived does not overload the operators, this
        //will succeed - the definition in MyDerived will be used.
        if (a == b)
        {
            //Reached, because the operator in MyDerived is used.
            Console.WriteLine("MyDerived operator used: a == b");
        }

        a.fderived = 2;
        b.fbase = 1;
        //a => {1, 2} 
        //b => {1, 3}
        //Since 2 != 3, the operator in MyDerived would return false.
        //However only the operator in MyBase will be used.
        if ((MyBase)a == (MyBase)b)
        {
            //Reached, because the operator in MyBase is used.
            Console.WriteLine("MyBase operator used: a == b");
        }

        b.fderived = 2;
        //a => {1, 2} 
        //b => {1, 2}
        //Now both operator definitions would compare equal,
        //however they are not used.
        if ((object)a != (object)b)
        {
            //Reached, because the default implementation is used
            //and the references are not equal.
            Console.WriteLine("Default operator used: a != b");
        }

    }

    class MyBase
    {
        public int fbase;

        public static bool operator ==(MyBase x, MyBase y)
        {
            return x.fbase == y.fbase;
        }

        public static bool operator !=(MyBase x, MyBase y)
        {
            return x.fbase != y.fbase;
        }

    }

    class MyDerived : MyBase
    {
        public int fderived;

        public static bool operator ==(MyDerived x, MyDerived y)
        {
            return x.fderived == y.fderived;
        }

        public static bool operator !=(MyDerived x, MyDerived y)
        {
            return x.fderived != y.fderived;
        }

    }

    class MyMoreDerived : MyDerived
    {
    }

}

单例在引用类型的上下文中最有意义,它们的目的是返回一个特定的实例。我无法想象引用相同但对象不“等于”自身的合理情况。

即使使用远程处理,最佳实践也是将操作合同与数据合同分开。
前者通常由服务器端的 MarshalByRefObject 实现 - 实现由接口定义的操作 - 而后者则使用按值编组并可能由客户端和服务器共享的数据/消息类。如果您重载数据类中的运算符,这可能不是一个大问题。然而,我相信这些不应该引用/调用远程对象。

即使您提供了一个使运算符重载的自定义客户端代理,恕我直言,将远程调用隐藏在 ==!= 运算符后面也是一种非常糟糕的做法,也是调试的噩梦。
(如果我理解你的意图,我不确定。)

For user defined value types, your code won't compile.

Specifically, it would fail compilation with the following error: "Operator '==' cannot be applied to operands of type 'a' and 'a' ".

"The == and != operators cannot operate on a struct unless the struct explicitly overloads them."

You have to overload both of them. You most probably do not want to utilize the default Equals() in your method, since
"...for structs, the default implementation of Object.Equals(Object) (which is the overridden version in System.ValueType) performs a value equality check by using reflection to compare the values of every field in the type. When an implementer overrides the virtual Equals method in a stuct, the purpose is to provide a more efficient means of performing the value equality check and optionally to base the comparison on some subset of the struct's field or properties."

For user defined reference types (simplified case, as in the OP's example):

"The == and != operators can be used with classes even if the class does not overload them. However, the default behavior is to perform a reference equality check. In a class, if you overload the Equals method, you should overload the == and != operators, but it is not required."

If you do not overload the operators, there will most probably only be a reference equality test.

"Simplified case", because operator overload resolution might select another implementation instead of the default.

//Minimal example, for demonstration only.
//No Equals(), GetHaschode() overload, no IEquatable<T>, null checks, etc..
class Program
{
    static void Main()
    {

        MyMoreDerived a = new MyMoreDerived() { fbase = 1, fderived = 3 };
        MyMoreDerived b = new MyMoreDerived() { fbase = 2, fderived = 3 };

        //Even though MyMoreDerived does not overload the operators, this
        //will succeed - the definition in MyDerived will be used.
        if (a == b)
        {
            //Reached, because the operator in MyDerived is used.
            Console.WriteLine("MyDerived operator used: a == b");
        }

        a.fderived = 2;
        b.fbase = 1;
        //a => {1, 2} 
        //b => {1, 3}
        //Since 2 != 3, the operator in MyDerived would return false.
        //However only the operator in MyBase will be used.
        if ((MyBase)a == (MyBase)b)
        {
            //Reached, because the operator in MyBase is used.
            Console.WriteLine("MyBase operator used: a == b");
        }

        b.fderived = 2;
        //a => {1, 2} 
        //b => {1, 2}
        //Now both operator definitions would compare equal,
        //however they are not used.
        if ((object)a != (object)b)
        {
            //Reached, because the default implementation is used
            //and the references are not equal.
            Console.WriteLine("Default operator used: a != b");
        }

    }

    class MyBase
    {
        public int fbase;

        public static bool operator ==(MyBase x, MyBase y)
        {
            return x.fbase == y.fbase;
        }

        public static bool operator !=(MyBase x, MyBase y)
        {
            return x.fbase != y.fbase;
        }

    }

    class MyDerived : MyBase
    {
        public int fderived;

        public static bool operator ==(MyDerived x, MyDerived y)
        {
            return x.fderived == y.fderived;
        }

        public static bool operator !=(MyDerived x, MyDerived y)
        {
            return x.fderived != y.fderived;
        }

    }

    class MyMoreDerived : MyDerived
    {
    }

}

Singletons are most meaningful in the context of reference types and their purpose is to return one specific instance. I cannot imagine a reasonable case where the reference is the same but the object is not "equal" to itself.

Even with remoting it is best practice to separate operation contracts from data contracts.
The former will typically be implemented by MarshalByRefObjects on the server side - implementing operations defined by interfaces - while the latter with data/message classes that are marshaled by value and might be shared by the client and server. It might not be a big problem if you overload the operators in data classes. These, however should not reference/make calls to remote objects, I believe.

Even if you provide a custom client proxy that overloads the operators, imho it is a really bad practice and a debugging nightmare to hide remoting calls behind == and != operators.
(If I understand your intentions, that I am not sure of.)

∞觅青森が 2024-09-01 12:09:03

它可能会比较指针“a”和“b”,看它们是否指向内存中的同一对象。

如果您需要比较这些对象的字段,则必须定义比较器函数。

您需要继承 IComparable 接口并定义 CompareTo 方法。

看这里:IComparable 接口

It will likely compare pointers 'a' and 'b', whether they point to the same object in memory.

If you need to compare fields of those objects, you'll have to define the comparer function.

You'll need to inherit from IComparable interface and define the CompareTo method.

Look here: IComparable Interface

旧街凉风 2024-09-01 12:09:03

当 == 没有被重写时,我相信它会比较引用,检查它们是否是同一个对象。

示例:

MyClass a = new MyClass(1);
MyClass b = new MyClass(1);
MyClass c = a;

if (a == b) // false
    ...
if (a == c) // true
    ...

因此,在上面的代码中,cmp1 将为 false,但 cmp2 将为 true

对于用户定义的值类型,但是,它会比较该类型的实际值。

When == is not overridden, I believe it compares references, checking if they are the same object.

Example:

MyClass a = new MyClass(1);
MyClass b = new MyClass(1);
MyClass c = a;

if (a == b) // false
    ...
if (a == c) // true
    ...

So therefore, in your code above, cmp1 would be false, but cmp2 would be true

For user defined value types, however, it compares the actual value of the type.

以酷 2024-09-01 12:09:03

来自 MSDN:

对于预定义值类型,相等运算符 (==) 如果其操作数的值相等则返回 true,否则返回 false。 对于字符串以外的引用类型,如果两个操作数引用同一个对象,则 == 返回 true。对于字符串类型,== 比较字符串的值。

From MSDN:

For predefined value types, the equality operator (==) returns true if the values of its operands are equal, false otherwise. For reference types other than string, == returns true if its two operands refer to the same object. For the string type, == compares the values of the strings.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文