为什么一定要同时定义==和!=在C#中? [英] Why must we define both == and != in C#?

查看:120
本文介绍了为什么一定要同时定义==和!=在C#中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C#编译器需要,每当一个自定义的类型定义运算符 == ,它也必须定义!= (看到这里 href=\"http://msdn.microsoft.com/en-us/library/ms173147%28v=vs.80%29.aspx\">)。

The C# compiler requires that whenever a custom type defines operator ==, it must also define != (see here).

为什么?

我很好奇,想知道为什么设计师认为有必要,为什么不能编译器默认到一个合理的实施无论是当只有另一个是present运营商。例如,Lua中让你只定义相等操作符,你会得到另一个免费的。 C#可以通过要求你定义要么做同样的==或两者==和!=,然后自动编译缺失!=运算符为!(左==右)

I'm curious to know why the designers thought it necessary and why can't the compiler default to a reasonable implementation for either of the operators when only the other is present. For example, Lua lets you define only the equality operator and you get the other for free. C# could do the same by asking you to define either == or both == and != and then automatically compile the missing != operator as !(left == right).

据我所知,有怪异的角落情况下,一些实体可能既不等于也不是不平等的,(如IEEE-754楠的),但这些似乎是例外,而不是规则。因此,这并不能解释为什么C#编译器设计者作了例外的规定。

I understand that there are weird corner cases where some entities may neither be equal nor unequal, (like IEEE-754 NaN's), but those seem like the exception, not the rule. So this doesn't explain why the C# compiler designers made the exception the rule.

我看到那里的相等运算符的定义是做工差的情况下,那么不平等运营商是一个复制粘贴与每逆转每个比较,每个&功放;&安培;切换到|| (你明白了吧...基本上!(一== b)透过德·摩根的规则展开​​)。这是不良的做法,编译器可以通过设计消除,如与Lua的情况。

I've seen cases of poor workmanship where the equality operator is defined, then the inequality operator is a copy-paste with each and every comparison reversed and every && switched to a || (you get the point... basically !(a==b) expanded through De Morgan's rules). That's poor practice that the compiler could eliminate by design, as is the case with Lua.

请注意:
这同样适用于运营商&下; >< => =。我无法想象,你就需要在不自然的方式来定义这些案件。 Lua中,您可以定义只<和< =,并且限定> =和>自然通过前人否定。为什么不C#做同样的('默认'至少)?

Note: The same holds for operators < > <= >=. I can't imagine cases where you'll need to define these in unnatural ways. Lua lets you define only < and <= and defines >= and > naturally through the formers' negation. Why doesn't C# do the same (at least 'by default')?

修改

显然有正当理由,允许程序员来实现的但是他们喜欢平等和不平等检查。一些问题的答案指向的情况下,可能是很好的。

Apparently there are valid reasons to allow the programmer to implement checks for equality and inequality however they like. Some of the answers point to cases where that may be nice.

我的问题的核心,但是,为什么这种被强制在C#中需要时的一般的它不是的逻辑的必要吗?

The kernel of my question, however, is why this is forcibly required in C# when usually it's not logically necessary?

这也是鲜明的对比设计像的Object.Equals IEquatable.Equals .NET接口的选择 IEqualityComparer.Equals ,其中缺少 NotEquals 对应的显示,该框架认为!等于( )对象作为不平等的,就是这样。此外,如词典键,如方法。载有()类完全依赖于上述接口,没有使用运营商直接即使它们被定义。事实上,当ReSharper的产生平等的成员,它定义了 == != 而言等于(),即使这样仅当用户选择在所有产生的运营商。不需要由框架的相等运算符来了解对象的相等。

It is also in striking contrast to design choices for .NET interfaces like Object.Equals, IEquatable.Equals IEqualityComparer.Equals where the lack of a NotEquals counterpart shows that the framework considers !Equals() objects as unequal and that's that. Furthermore, classes like Dictionary and methods like .Contains() depend exclusively on the aforementioned interfaces and do not use the operators directly even if they are defined. In fact, when ReSharper generates equality members, it defines both == and != in terms of Equals() and even then only if the user chooses to generate operators at all. The equality operators aren't needed by the framework to understand object equality.

基本上,.NET框架不关心这些运营商来说,只关心几个等于方法。决定要求这两个==和!=在串联由用户定义的运营商,纯粹是有关语言设计和尽可能.NET而言不会反对的语义。

Basically, the .NET framework doesn't care about these operators, it only cares about a few Equals methods. The decision to require both == and != operators to be defined in tandem by the user is related purely to the language design and not object semantics as far as .NET is concerned.

推荐答案

我不能为语言设计者说,但是从我可以讲道理的,现在看来似乎是故意的,正确的设计决策。

I can't speak for the language designers, but from what I can reason on, it seems like it was intentional, proper design decision.

看着这个基本的F#code,可以编译成一个工作库这一点。这是合法的code F#的,只有重载运营商的平等,而不是不等式:

Looking at this basic F# code, you can compile this into a working library. This is legal code for F#, and only overloads the equality operator, not the inequality:

module Module1

type Foo() =
    let mutable myInternalValue = 0
    member this.Prop
        with get () = myInternalValue
        and set (value) = myInternalValue <- value

    static member op_Equality (left : Foo, right : Foo) = left.Prop = right.Prop
    //static member op_Inequality (left : Foo, right : Foo) = left.Prop <> right.Prop

这也正是它的样子。它创建在一个相等比较 == 只,并检查是否类的内在价值是相等的。

This does exactly what it looks like. It creates an equality comparer on == only, and checks to see if the internal values of the class are equal.

虽然您不能创建在C#这样的一类,你的可以的使用一个被编译为.NET。很明显它会使用我们的重载运算符 == 那么,是什么在运行时使用了!=

While you can't create a class like this in C#, you can use one that was compiled for .NET. It's obvious it will use our overloaded operator for == So, what does the runtime use for !=?

C#的EMCA标准都有一大堆规则(14.9节)解释如何确定哪些运营商评估平等时使用。把它过于简化,因此不完全准确的,如果被比较的类型相同类型的<青霉>和的存在是一个重载相等运算present,它将使用过载和不标准参考相等运算符从Object继承。这是毫不奇怪,那么,如果只有运营商之一是present,它会使用默认的引用相等运营商,所有的对象有,有没有为它的过载。 1

The C# EMCA standard has a whole bunch of rules (section 14.9) explaining how to determine which operator to use when evaluating equality. To put it overly-simplified and thus not perfectly accurate, if the types that are being compared are of the same type and there is an overloaded equality operator present, it will use that overload and not the standard reference equality operator inherited from Object. It is no surprise, then, that if only one of the operators is present, it will use the default reference equality operator, that all objects have, there is not an overload for it.1

明知这种情况下,真正的问题是:为什么这个设计以这种方式,为什么不编译器算起来自身?很多人都在说,这是不是设计的决定,但我喜欢把它想出来这种方式,特别是关于事实的所有对象都有一个默认的相等运算符。

Knowing that this is the case, the real question is: Why was this designed in this way and why doesn't the compiler figure it out on its own? A lot people are saying this wasn't a design decision, but I like to think it was thought out this way, especially regarding the fact all objects have a default equality operator.

那么,为什么不编译器自动的创建!= 运营商?我不能肯定知道,除非微软有人证实了这一点,但是这是我可以从推理上的事实判断。

So, why doesn't the compiler automagically create the != operator? I can't know for sure unless someone from Microsoft confirms this, but this is what I can determine from reasoning on the facts.

也许,我想对 A值比较== 测试平等。但是,当它来到!= 我不在乎在所有的值是否相等,除非参考等于,因为我的程序来考虑他们平等的,我只关心,如果引用匹配。毕竟,这实际上是概括为C#中的默认行为(如果两个经营者不超载,因为是在用其它语言编写的一些.NET库的情况下)。如果编译器在code自动添加,我可以不再依赖于编译器输出code这应该是标准。编译器不应该写隐藏code,改变你的行为,尤其是当你已经写了code是C#和CLI的标准之内。

Perhaps I want to do a value comparison on == to test equality. However, when it came to != I didn't care at all if the values were equal unless the reference was equal, because for my program to consider them equal, I only care if the references match. After all, this is actually outlined as default behavior of the C# (if both operators were not overloaded, as would be in case of some .net libraries written in another language). If the compiler was adding in code automatically, I could no longer rely on the compiler to output code that should is compliant. The compiler should not write hidden code that changes the behavior of yours, especially when the code you've written is within standards of both C# and the CLI.

在它的强制的你重载它,而不是去默认行为,我只能坚定地说,它是在标准(EMCA-334 17.9.2)条款2 。该标准没有具体说明原因。我相信这是由于C#从C借鉴了很多行为++的事实。详情请参阅下面这一点。

In terms of it forcing you to overload it, instead of going to the default behavior, I can only firmly say that it is in the standard (EMCA-334 17.9.2)2. The standard does not specify why. I believe this is due to the fact that C# borrows much behavior from C++. See below for more on this.

这是另一个可能的原因。在C#中,此功能:

This is another likely reason. In C#, this function:

public static int operator ==(MyClass a, MyClass b) { return 0; }

是有效的,这一个:

is as valid as this one:

public static bool operator ==(MyClass a, MyClass b) { return true; }

如果你正在返回比其他布尔东西,编译器的无法的自动推断出相反的类型。此外,在操作员的的回报布尔,它只是没有意义为他们创造产生code正如我上面所说,将只在一个特定的情况下或存在的情况下, code,它隐藏了CLR的默认行为。

If you're returning something other than bool, the compiler cannot automatically infer an opposite type. Furthermore, in the case where your operator does return bool, it just doesn't make sense for them create generate code that would only exist in that one specific case or, as I said above, code that hides the default behavior of the CLR.

在引入C#中,有在MSDN杂志的一篇文章写到这,谈论C#:

When C# was introduced, there was an article in MSDN magazine that wrote, talking about C#:

许多开发人员希望有一个易于读,写和维护如Visual Basic语言,但是仍然提供了C ++的强大功能和灵活性。

Many developers wish there was a language that was easy to write, read, and maintain like Visual Basic, but that still provided the power and flexibility of C++.

是为C#设计目标是给几乎相同数量的权力,C ++,只有牺牲有点像硬质类型安全和垃圾收集设施。 C#C ++后,极力模仿。

Yes the design goal for C# was to give nearly the same amount of power as C++, sacrificing only a little for conveniences like rigid type-safety and garbage-collection. C# was strongly modeled after C++.

您可能不惊讶地得知,在C ++中,在平等运营商没有返回布尔,如这个例子程序

You may not be surprised to learn that in C++, the equality operators do not have to return bool, as shown in this example program

现在,C ++没有直接的需要的你重载免费运营。如果您编译示例程序的code,你会看到它没有错误运行。但是,如果你尝试添加行:

Now, C++ does not directly require you to overload the complimentary operator. If your compiled the code in the example program, you will see it runs with no errors. However, if you tried adding the line:

cout << (a != b);

您将获得

编译器错误C2678(MSVC):二进制'!=':没有操作员发现这需要类型的左侧操作数'测试'(或没有可接受的转换)`

compiler error C2678 (MSVC) : binary '!=' : no operator found which takes a left-hand operand of type 'Test' (or there is no acceptable conversion)`.

所以,虽然C ++本身并不需要你成双成对过载,它的不会让你使用,你有没有对自定义类重载相等运算符。它在.NET有效的,因为所有的对象都有一个默认的; C ++没有。

So, while C++ itself doesn't require you to overload in pairs, it will not let you use an equality operator that you haven't overloaded on a custom class. It's valid in .NET, because all objects have a default one; C++ does not.

1。作为一个侧面说明,C#标准仍然需要你,如果你想重载任何一个超载对运营商。这是的标准的,而不是简单的的编译的一部分。然而,关于确定相同的规则哪家运营商的来电,当你访问其他语言编写一个.NET库,不具有相同的要求适用。

1. As a side note, the C# standard still requires you to overload the pair of operators if you want to overload either one. This is a part of the standard and not simply the compiler. However, the same rules regarding the determination of which operator to call apply when you're accessing a .net library written in another language that doesn't have the same requirements.

2。 EMCA-334(PDF)(HTTP://www.ecma -international.org/publications/files/ECMA-ST/Ecma-334.pdf)

2. EMCA-334 (pdf) (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf)

3。和Java,但是这真的不是在这里点

这篇关于为什么一定要同时定义==和!=在C#中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆