爲何咱們必須在C#中同時定義==和!=?

C#編譯器要求,每當自定義類型定義運算符== ,它還必須定義!= (請參見此處 )。 程序員

爲何? 框架

我很好奇,爲何設計師會認爲這是必要的,以及爲何當僅存在另外一個運算符時,編譯器爲什麼不能默認其中一個運算符爲合理的實現。 例如,Lua容許您僅定義相等運算符,而另外一個則免費。 C#能夠經過要求您定義==或同時定義==和!=來完成相同的工做,而後將缺乏的!=運算符自動編譯爲!(left == right)測試

我知道有些狀況下有些實體可能不相等或不相等(例如IEEE-754 NaN),可是在某些特殊狀況下,這彷佛是個例外,而不是規則。 所以,這不能解釋爲何C#編譯器設計人員將例外做爲規則。 spa

我已經看到了定義平等運算符的工藝不佳的狀況,而後不平等運算符是一個複製粘貼,每一個比較都相反,每一個&&切換爲||。 (您明白了……基本上!(a == b)經過De Morgan的規則擴展了)。 與Lua的狀況同樣,編譯器能夠經過設計消除這種糟糕的作法。 .net

注意:運算符<> <=> =也是如此。 我沒法想象須要用不天然的方式定義它們的狀況。 Lua容許您僅定義<和<=,並經過前者的否認天然定義> =和>。 C#爲何不作一樣的事情(至少是「默認」)? 設計

編輯 code

顯然,有充分的理由容許程序員執行他們喜歡的相等性和不平等性檢查。 一些答案指出了可能不錯的狀況。 對象

可是,個人問題的核心是,爲何在C#中一般邏輯上沒必要要時強制執行此操做? 接口

它與.NET接口(如Object.EqualsIEquatable.Equals IEqualityComparer.Equals設計選擇造成鮮明對比,在缺乏NotEquals對應項的狀況下,該框架認爲!Equals()對象是不相等的,僅此NotEquals 。 此外,諸如Dictionary類的類和諸如.Contains()類的方法.Contains()取決於上述接口,即便定義了它們也不會直接使用運算符。 實際上,當ReSharper生成相等成員時,它會根據Equals()定義==!= ,而且即便在用戶選擇徹底生成運算符的狀況下也是如此。 框架不須要相等運算符來了解對象相等。 字符串

基本上,.NET框架不關心這些運算符,而僅關心一些Equals方法。 要求用戶同時定義==和!=運算符的決定徹底與語言設計有關,而就.NET而言,與對象語義無關。


#1樓

可能只是他們沒有想到的事情而沒有時間去作。

當我重載==時,我老是使用您的方法。 而後,我只在另外一箇中使用它。

您是對的,只需少許工做,編譯器即可以避免費將其提供給咱們。


#2樓

好吧,這可能只是設計選擇,可是正如您所說, x!= y沒必要與!(x == y) 。 經過不添加默認實現,能夠確保您不會忘記實現特定實現。 並且,若是確實如您所說的那樣瑣碎,則能夠僅使用另外一個實現。 我看不出這是「不良作法」。

C#和Lua之間可能還有其餘差別...


#3樓

多是由於有人須要實現三值邏輯(即null )。 在這種狀況下-例如ANSI標準SQL-不能簡單地根據輸入否認運算符。

您可能遇到如下狀況:

var a = SomeObject();

a == true返回falsea == false也返回false


#4樓

除了C#在許多方面適合C ++以外,我能想到的最好解釋是,在某些狀況下,您可能想採用稍微不一樣的方法來證實「不平等」而不是證實「平等」。

顯然,用字符串比較,例如,你能夠只測試平等和return循環了,當你看到非匹配的字符。 可是,它可能沒有那麼複雜的問題。 我想到了綻開過濾器 ; 快速判斷元素是否不在集合中很是容易,可是很難判斷元素是否在集合中。 儘管可使用相同的return技術,但代碼可能並不那麼漂亮。


#5樓

若是您在.net源代碼中查看==和!=重載的實現,則它們一般不會將!=實現爲!(左==右)。 他們使用否認邏輯徹底實現了它(例如==)。 例如,DateTime將==實現爲

return d1.InternalTicks == d2.InternalTicks;

和!= as

return d1.InternalTicks != d2.InternalTicks;

若是您(或編譯器(若是隱式執行))將實現=

return !(d1==d2);

那麼您將在類引用中對==和!=的內部實現進行假設。 避免這種假設多是他們決定背後的哲學。

相關文章
相關標籤/搜索