いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

.NET クラスライブラリ探訪-012 (System.Collections.Generic.Dictionary)(02)

Dictionaryクラスが、キーの比較処理を行う際に何を見ているかは以下で決まります。

コンストラクタにIEqualityComparer実装クラスを渡している場合、それを利用してキーの比較処理を行う。
■コンストラクタにIEqualityComparer実装クラスを渡していない場合、既定のEqualityComparerオブジェクトが使用されます。
 その場合、キーオブジェクトのEquals(), GetHashCode()をコールしてキーの比較処理が行われます。


つまり、独自の比較処理をしたい場合は以下のようにして実装すればいいことになります。

■そのクラスのEquals, GetHashCodeをオーバーライドする。
■そのクラス用のIEqualityComparerを作成して、それを渡す。


この辺の概念はJavaと大体同じですね。


実は他にもSystem.IEquatableというジェネリックインターフェースがありまして、そいつのEqualsメソッドと
object.GetHashCodeメソッドを組み合わせて利用するというのもありますが今回は割愛します。
あまり使いそうにないので・・・・w


ちなみに、object.Equals()とIEquatable.Equalsを両方実装した上でDictionaryにキー登録している場合は
IEquatable.Equalsの方が優先されます。


以下、サンプルです。

using System;
using System.Collections.Generic;
using System.Text;

namespace Gsf.Samples.ClassLibraryResearch.System.Collections.Generic {

    /// <summary>
    /// 単純にobjectクラスのEquals,GetHashCodeをオーバーライドしたクラスです。
    /// </summary>
    public class SampleKeyClass{

        string _id;
        string _name;

        public SampleKeyClass(string id, string name){
            _id   = id;
            _name = name;
        }

        public string Id{
            get{
                return _id;
            }
        }

        public override bool Equals(object o) {
            SampleKeyClass other = null;
            if(o == null || (other = o as SampleKeyClass) == null){
                return false;
            }

            return Id == other.Id;
        }

        public override int GetHashCode() {
            return Id.GetHashCode();
        }

        public override string ToString() {
            return string.Format("id:{0}, name:{1}", _id, _name);
        }
    }


    /// <summary>
    /// 内部に比較処理用のIEqualityComparerオブジェクトを持つサンプルクラスです。
    /// Comparer静的フィールドより、取得できます。
    /// </summary>
    public class SampleKeyClass2 {

        /// <summary>
        /// SampleKeyClass2用のIEqualityComparerの実装です。
        /// </summary>
        class _Comparer : IEqualityComparer<SampleKeyClass2> {

            public bool Equals(SampleKeyClass2 x, SampleKeyClass2 y) {
                return x.Id == y.Id;
            }

            public int GetHashCode(SampleKeyClass2 obj) {
                return obj.Id.GetHashCode();
            }
        }

        /// <summary>
        /// このクラス用のIEqualityComparerの実装です。
        /// </summary>
        public static readonly IEqualityComparer<SampleKeyClass2> Comparer = new _Comparer();

        string _id;
        string _name;

        public SampleKeyClass2(string id, string name){
            _id   = id;
            _name = name;
        }

        public string Id{
            get{
                return _id;
            }
        }

        public override string ToString() {
            return string.Format("id:{0}, name:{1}", _id, _name);
        }
    }


    /// <summary>
    /// System.Collections.Generic.Dictionaryクラスのサンプルです。
    /// </summary>
    /// <remarks>
    /// Dictionaryクラスが、キーの比較処理を行う際に何を見ているかは以下で決まります。
    /// 
    /// ■コンストラクタにIEqualityComparer実装クラスを渡している場合、それを利用してキーの比較処理を行う。
    /// ■コンストラクタにIEqualityComparer実装クラスを渡していない場合、既定のEqualityComparerオブジェクトが使用されます。
    ///  その場合、キーオブジェクトのEquals(), GetHashCode()をコールしてキーの比較処理が行われます。
    /// 
    /// つまり、独自の比較処理をしたい場合は以下のようにして実装すればいいことになります。
    /// 
    /// ■そのクラスのEquals, GetHashCodeをオーバーライドする。
    /// ■そのクラス用のIEqualityComparerを作成して、それを渡す。
    /// 
    /// 実は他にもSystem.IEquatableというジェネリックインターフェースがありまして、そいつのEqualsメソッドと
    /// object.GetHashCodeメソッドを組み合わせて利用するというのもありますが今回は割愛します。
    /// あまり使いそうにないので・・・・w
    /// 
    /// ちなみに、object.Equals()とIEquatable.Equalsを両方実装した上でDictionaryにキー登録している場合は
    /// IEquatable.Equalsの方が優先されます。
    /// </remarks>
    public class DictionaryResearcher2 : IExecutable{

        public void Execute() {
            //
            // 普通のクラスにて、objectクラスのEquals,GetHashCodeをオーバーライドした
            // ものをキーとして利用してみます。
            //
            SampleKeyClass key1 = new SampleKeyClass("1", "gsf_zero1");
            SampleKeyClass key2 = new SampleKeyClass("2", "gsf_zero2");
            SampleKeyClass key3 = new SampleKeyClass("3", "gsf_zero3");

            Dictionary<SampleKeyClass, int> dict1 = new Dictionary<SampleKeyClass,int>();
            dict1[key1] = 10;
            dict1[key2] = 20;
            dict1[key3] = 30;

            Console.WriteLine("idが2のものを取得:{0}", dict1[new SampleKeyClass("2", "")]);
            Console.WriteLine("idが3のものを取得:{0}", dict1[new SampleKeyClass("3", "gsf_zero1")]);

            //
            // キークラス自身には、Equals,GetHashCodeは実装していないが代わりに
            // IEqualityComparerの独自実装をDictionaryに渡してキーの比較処理を行ってみます。
            //
            SampleKeyClass2 key4 = new SampleKeyClass2("4", "gsf_zero4");
            SampleKeyClass2 key5 = new SampleKeyClass2("5", "gsf_zero5");

            Dictionary<SampleKeyClass2, int> dict2 = new Dictionary<SampleKeyClass2,int>(SampleKeyClass2.Comparer);
            dict2[key4] = 40;
            dict2[key5] = 50;

            Console.WriteLine("idが4のものを取得:{0}", dict2[new SampleKeyClass2("4", "")]);
            Console.WriteLine("idが5のものを取得:{0}", dict2[new SampleKeyClass2("5", "gsf_zero1")]);
        }
    }


    class EntryPoint {
        
        static void Main(){
            new DictionaryResearcher2().Execute();
        }
    }
}

================================
過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。