中の技術日誌
 ホーム / 上へ

技術解説 .NET 2.0 ジェネリック(Generics)  第6回 IEqualityComparer<T>とDictionary(IEqualityComparer<T>)

2006/01/26

この文書はVisual Studio 2005をベースに記述されています。製品版や、あなたが読んでいる時点では変更されている可能性があります。

第6回 IEqualityComparer<T>とDictionary(IEqualityComparer<T>)

.NET1.xの世界ではIComparerというインターフェイスはobjとobjを比較するもので、どうしてもキャストしないといけないものであった。

.NET2.0ではIComparer<T>というものが導入されることになるが、DictionaryではIEqualityComparer<T>を利用する。

これを利用すると、Dictionary<TKey, TValue>のKeyに独自のクラスを設定したりする場合に非常に便利になる。

まず利用するクラスを下記のように定義する。

下記が実際のクラス定義

public class 商品Key
{
  public string 商品コード;
  public string カラー;
}
public class 商品
{
  public string 商品コード;
  public string カラー;
  public string 一般商品名;
  public decimal 希望小売価格;
  public 商品Key 商品Key
  {
    get
    {
      商品Key key = new 商品Key();
      key.商品コード = this.商品コード;
      key.カラー = this.カラー;
      return key;
    }
  }
}
public class 商品Comparer : IEqualityComparer<商品Key>
{
  public bool Equals(商品Key x, 商品Key y)
  {
    if (x.商品コード == y.商品コード && x.カラー == y.カラー)
    {
      return true;
    }
    else
    {
      return false;
    }
  }
  public int GetHashCode(商品Key obj)
  {
    string HashData = string.Format("商品コード:{0}\r\nカラー:{1}", obj.商品コード, obj.カラー);
    return HashData.GetHashCode();
  }
}
Public Class 商品Key
  Public 商品コード As String
  Public カラー As String
End Class
Public Class 商品
  Public 商品コード As String
  Public カラー As String
  Public 一般商品名 As String
  Public 希望小売価格 As Decimal
  Public ReadOnly Property 商品Key() As 商品Key
    Get
      Dim key As 商品Key = New 商品Key()
      key.商品コード = Me.商品コード
      key.カラー = Me.カラー
      Return key
    End Get
  End Property
End Class
Public Class 商品Comparer
  Implements IEqualityComparer(Of 商品Key)
  Public Function Equals1(ByVal x As 商品Key, ByVal y As 商品Key) As Boolean Implements System.Collections.Generic.IEqualityComparer(Of 商品Key).Equals
    If (x.商品コード = y.商品コード And x.カラー = y.カラー) Then
      Equals1 = True
    Else
      Equals1 = False
    End If
  End Function
  Public Function GetHashCode1(ByVal obj As 商品Key) As Integer Implements System.Collections.Generic.IEqualityComparer(Of 商品Key).GetHashCode
    Dim HashData As String = String.Format("商品コード:{0}\r\nカラー:{1}", obj.商品コード, obj.カラー)
    GetHashCode1 = HashData.GetHashCode()
  End Function
End Class
public ref class 商品Key : public System::Object
{
public:
  String^ 商品コード;
  String^ カラー;
};
public ref class 商品 : public System::Object
{
public:
  String^ 商品コード;
  String^ カラー;
  String^ 一般商品名;
  Decimal^ 希望小売価格;
  商品Key^ get商品Key()
  {
    商品Key^ key = gcnew 商品Key();
    key->商品コード = this->商品コード;
    key->カラー = this->カラー;
    return key;
  }
};
public ref class 商品Comparer : System::Collections::Generic::IEqualityComparer<商品Key^>
{
public:

  virtual bool Equals(商品Key^ x, 商品Key^ y)
  {
    if (x->商品コード == y->商品コード && x->カラー == y->カラー)
    {
      return true;
    }
    else
    {
      return false;
    }
  }
  virtual int GetHashCode(商品Key^ obj)
  {
    String^ HashData = String::Format(L"商品コード:{0}\r\nカラー:{1}", obj->商品コード, obj->カラー);
    return HashData->GetHashCode();
  }
};

商品というクラスのうちの一部が実際のキーで、そのキーが複合キーの場合で、Dictionaryに格納するなどという場合以前までは直感的なコードは組めなかった。(ので今回は1.xソースは割愛)

2.0においてはDictionaryのキー検索ルーチンをIEqualityComparer<T>でより柔軟に設計することができる。

これだけのコードを組むと以下のルーチンでDictionary<T>に格納したり抜き出したりということができるようになる。

Dictionary<商品Key, 商品> dic = new Dictionary<商品Key, 商品>(new 商品Comparer());
商品 syo = new 商品();
syo.商品コード = "ABC00001";
syo.カラー = "Red";
syo.一般商品名 = "ドラゴンクエツト";
syo.希望小売価格 = 5000;
dic.Add(syo.商品Key, syo);
商品Key 検索キー = new 商品Key();
検索キー.商品コード = "ABC00001";
検索キー.カラー = "Red";
商品 syo2 = dic[検索キー];
MessageBox.Show(syo2.一般商品名);
Dim dic As Dictionary(Of 商品Key, 商品) = New Dictionary(Of 商品Key, 商品)(New 商品Comparer())
Dim syo As 商品 = New 商品()
syo.商品コード = "ABC00001"
syo.カラー = "Red"
syo.一般商品名 = "ドラゴンクエツト"
syo.希望小売価格 = 5000
dic.Add(syo.商品Key, syo)
Dim 検索キー As 商品Key = New 商品Key()
検索キー.商品コード = "ABC00001"
検索キー.カラー = "Red"
Dim syo2 As 商品 = dic(検索キー)
MessageBox.Show(syo2.一般商品名)
Dictionary<商品Key^, 商品^>^ dic = gcnew Dictionary<商品Key^, 商品^>(gcnew 商品Comparer());
商品^ syo = gcnew 商品();
syo->商品コード = "ABC00001";
syo->カラー = "Red";
syo->一般商品名 = "ドラゴンクエツト";
syo->希望小売価格 = gcnew Decimal(5000);
dic->Add(syo->get商品Key(), syo);
商品Key^ 検索キー = gcnew 商品Key();
検索キー->商品コード = "ABC00001";
検索キー->カラー = "Red";
商品^ syo2 = dic->default[検索キー];
MessageBox::Show(syo2->一般商品名);

利用する側のソースは3言語ともほとんど同一だが、クラスのほうはなかなか特徴が出ていて面白いソースになった。

皆さんはどのソースがお好みだろう。

[戻る] [進む]


2006/12/16 大阪勉強会#4 + 忘年会 登録受付中

中の技術日誌
コンテンツ
わんくま同盟
わんくま同盟
わんくま同盟
広告
バナー
MVP LOGO
MSMVP Visual C# Since 2004/04-2007/03
MCP LOGO
070-316
姉妹サイト
姉妹サイト:じゃんぬのC#, VB.NET 入門
じゃんぬの
C#, VB.NET 入門
検索
Google

ブログ本家
広告