2014-03-01 23 views
0

可以使字典中的第一個類型成爲引用類型? 如果是的話,那是什麼意思?字典中的引用類型

using System.Collections.Generic; 
... 
Dictionary<T1, T2> myDict = new Dictionary<T1, T2>(); 

據我所知,第一種類型 - 是關鍵。而且比intstring更經常。

+1

是的,你可以使用引用類型作爲'TKey'。它實際上並不重要,如果它是一個結構或一個類。我不明白你爲什麼認爲它沒有意義。 – MarcinJuraszek

+0

嘗試一下,看看它是否可能。 –

+2

你知道'string'是一個類(也就是引用類型),對吧? –

回答

4

使用引用類型作爲字典中的鍵是很好的。重要的是要記住,如果你這樣做,是引用類型使用引用相等作爲默認值。

如果您希望鍵類型的多個實例表示相同的值,那麼您需要確保引用類型使用值相等。例如,string是一個已經支持值相等的引用類型,因此使用字符串作爲密鑰是安全和容易的。

問題:

以下引用類型沒有實現價值的平等:

class Foo 
{ 
    public int X { get; set; } 
} 

所以,如果你創建兩個實例,拿着同樣的價值,他們不認爲是相等的:

var a = new Foo { X = 1 }; 
var b = new Foo { X = 1 }; 
Console.WriteLine(a == b); // false 
Console.WriteLine(a.Equals(b)); // false 

如果您使用a作爲關鍵字將值存儲在字典中,那麼您將不會被abl e。使用b找回它:

var dict = new Dictionary<Foo, int>(); 
dict[a] = 10; 
Console.WriteLine(dict[b]); // Key not found exception 

解決方案

爲了解決這個問題,你可以(我)實現價值平等的類型,或(II)重寫你的字典比較鑰匙的方式:

選項I:實現價值的平等:

所以,如果你是要實現價值的平等,供您參考鍵入您應該遵循these guidelines,這會給你這樣的事情(不要忘記GetHashCode):

class Foo2 : IEquatable<Foo2> 
{ 
    public int X { get; set; } 

    public override bool Equals(object obj) 
    { 
     return this.Equals(obj as Foo2); 
    } 

    public bool Equals(Foo2 other) 
    { 
     if (Object.ReferenceEquals(other, null)) 
     { 
      return false; 
     } 

     // Optimization for a common success case. 
     if (Object.ReferenceEquals(this, other)) 
     { 
      return true; 
     } 

     if (this.GetType() != other.GetType()) 
      return false; 

     return (X == other.X); 
    } 

    public override int GetHashCode() 
    { 
     return this.X; 
    } 

    public static bool operator ==(Foo2 lhs, Foo2 rhs) 
    { 
     if (Object.ReferenceEquals(lhs, null)) 
     { 
      if (Object.ReferenceEquals(rhs, null)) 
      { 
       return true; 
      } 

      return false; 
     } 

     return lhs.Equals(rhs); 
    } 

    public static bool operator !=(Foo2 lhs, Foo2 rhs) 
    { 
     return !(lhs == rhs); 
    } 
} 

現在表示相同值的Foo2兩個實例被認爲是相等:

var c = new Foo2 { X = 1 }; 
var d = new Foo2 { X = 1 }; 
Console.WriteLine(c == d); // true 
Console.WriteLine(c.Equals(d)); // true 

如果使用c作爲密鑰將值存儲在字典中,則您的能夠使用d檢索它:

var dict = new Dictionary<Foo2, int>(); 
dict[c] = 10; 
Console.WriteLine(dict[d]); // 10 

方案二:使用自定義相等比較:

如果你不打算通常比較Foo情況,但還是希望能夠在字典中的比較時他們使用的值相等,就可以提供自定義相等比較器,以替代實現全部價值的平等:

class FooComparer : IEqualityComparer<Foo> 
{ 

    public bool Equals(Foo x, Foo y) 
    { 
     // Doesn't handle null arguments! 
     return x.X == y.X; 
    } 

    public int GetHashCode(Foo obj) 
    { 
     return obj.X; 
    } 
} 

ab仍然被認爲是不相等的,但現在你可以使用存儲在詞典中值,並採用b檢索:

var dict = new Dictionary<Foo, int>(new FooComparer()); 
dict[a] = 10; 
Console.WriteLine(dict[b]); // 10 
+0

+1爲完整樣本...另外改變一個類型只是爲了能夠用作字典中的鍵可能是矯枉過正,考慮實施'IEqualityComparer '並使用相應的[Dictionary 構造函數(IEqualityComparer )]( http://msdn.microsoft.com/en-us/library/ms132072%28v=vs.110%29.aspx) –

+0

@AlexeiLevenkov好點。我也添加了該選項的示例。 – Ergwun

2

在.NET框架中的每個對象有GetHashCodeEquals方法。而這些都是需要用作字典中的關鍵字。

默認引用類型使用引用相等(即鍵是內存中的同一對象),但您可以覆蓋GetHashCodeEquals以提供您喜歡的任何相等語義。

+0

+1。準確地說,即使在類型上實現'GetHashCode'和'Equals'方法也是不必要的 - [Dictionary(IEqualityComparer )](http://msdn.microsoft.com/en-us/library/ms132072%28v=vs。 110%29.aspx)允許使用任何對象作爲關鍵字,只要您提供適當的自定義比較器即可。 –