2010-08-12 64 views
2

這裏是我的簡單的代碼:爲什麼兩個泛型不能與'=='比較?

T a; 
T b; 

if (a == b) 
// sth. 
else 
// sth. else 

當我嘗試編譯,我得到一個錯誤說的==操作是泛型類型無效。所以我必須使用object.Equals()方法。

是不是==操作員實際上調用objectEquals方法?爲什麼我可以使用兩種通用類型的Equals方法,但不使用==運算符?

+1

我剛剛檢查,代碼示例似乎編譯(添加樣板和大括號後)。你能展示一個更全面的代碼示例嗎? – strager 2010-08-12 02:11:54

+7

David,你問了10個問題並接受了0個答案。你知道如何將正確答案標記爲已接受嗎? – 2010-08-12 02:13:12

+0

Nevermind ...似乎編譯器正在優化掉不必要的'a == b'比較,因爲它們都被設置爲'null'(或者某些;不完全確定)。 – strager 2010-08-12 02:26:08

回答

8

operator ==必須結構被重載以被使用,因此完全不受約束類型參數不能使用它。您可以約束功能class允許默認的基準進行比較:

public void Foo<T>() where T : class { 
     T a = default(T); 
     T b = a; 

     if(a == b) 
      System.Diagnostics.Debug.WriteLine(""); 
     else 
      System.Diagnostics.Debug.WriteLine(""); 
    } 

上面的代碼工作,因爲在默認情況下,引用類型可以用operator ==使用:

對於引用類型字符串以外, ==如果其兩個操作數引用同一個對象,則返回true。

這就是爲什麼if (new object() == new object()) {}編譯,即使System.Object不超載operator ==

2

==運算符沒有定義的T的所有可能值[感謝丹尼爾](或可能已放置於T的任何約束,我假設),所以可以不使用它。您只能撥打運營商的方法,可以由T.代表的所有可能的類型

==操作符調用在許多情況下,「等於」被調用,但這並不意味着對T的屬性他們是同樣的事情。

+2

實際上,運算符== *是*在對象上定義的,而不是在結構體上。對於大多數參考類型,==不調用.Equals。前者通常實現身份比較(不可變類型除外),後者通常實現價值比較。 – 2010-08-12 02:48:48

+0

使用ndepend進行的一項快速調查顯示,BCL中的大多數引用類型不定義運算符== - 爲它們提供ReferenceEquals而不是值比較行爲。 有趣的是,運算符==實際上並沒有在'object'上定義,只要我能看到 - 相反,我相信c#(或其他語言)編譯器最終編譯爲'.ceq',對於引用類型參考平等風格檢查。 – 2010-08-12 03:49:13

+0

我不''在'object'上定義。相反,當不存在對'=='的重載時,編譯器本身會嘗試將它解釋爲給定的特定類型的引用比較運算符,並查看是否有意義。運算符重載並不關心傳入的操作數是密封的還是非密封的,但是C#引用相等檢查運算符(引用的非密封類類型可以與其未實現的接口之一進行比較,而是引用到密封的班級不能)。 – supercat 2013-12-19 17:27:40

1

==令牌用於表示在C#的兩個不同的運營商。只有當操作數的類型符合「相等檢查」操作符的特定定義的重載時,它們才適用。第二個測試引用相等,只適用於一個操作數是null,一個操作數是類類型,另一個是該類型的實例可以實現的接口,它們都是接口,都是相同的類類型,或者都是類類型一個是另一個的超類型。第一種形式在泛型上不可用,除非泛型被限制爲定義了等式檢查過載的類型;第二種形式限於已知滿足特定條件的參考類型。請注意,在某些情況下,第二個操作員可以在第一個操作員想要的地方使用,例如, bool IsSame<T>(T p1, T p2) where T:class { return p1==p2; }將通過使用參考比較來比較String類型的兩個變量,即使爲String定義了==的過載。這是因爲T不是公知足夠適用的==String一個過載,但==兩個操作數是已知的相同的引用類型。

這可能是值得注意的是,一些其它語言使用不同的令牌的兩種操作C#進行使用==。例如,VB.NET使用=進行相等比較,Is用於參考相等。