5

私はこのようなコードを持っています:

if (CounterForEachRelatedTagDict.Select(x => x.Key).Contains(tag.Key))
   CounterForEachRelatedTagDict[tag.Key] += tag.Value;

IF ステートメントが true を返し、同時にCounterForEachRelatedTagDict[tag.Key]「指定されたキーが辞書に存在しませんでした」というエラーを返す可能性はありますか? tagですKeyValuePair<MyClass,int>

CounterForEachRelatedTagDict次のように開始されます。

Dictionary<MyClass, int> CounterForEachRelatedTagDict = new Dictionary<MyType, int>();

MyClassこのようなものです

public class MyClass
{
    public string name {get;set;}
    public Guid Id { get; set; }
    ...
}

それは私にはほとんど不合理に思えます...

4

3 に答える 3

4

問題は、EqualGetHashCodeメソッドが に対して同期していないことですMyType

を使用CounterForEachRelatedTagDict.Select(x => x.Key).Contains(tag.Key)すると、すべてのキーに対して線形検索を実行して、Equals検索対象を各キーと比較します。

ContainsKeyin 、インデクサー、またはキーを見つけるための他の多くの方法の 1 つを使用する場合Dictionary、最初に を使用してキーをハッシュしGetHashCode、次に を使用Equalsして、そのバケット内で同一であるオブジェクト (できれば非常に少数のオブジェクト) を検索します。

何が起こっているかというとfirst.Equals(second)、true を返すオブジェクトが 2 つあるのに、 GetHashCode2 つの異なる値を返すオブジェクトがあるということです。Dictionaryオブジェクトを a のキーとして使用する場合、 を返す2 つのオブジェクトも に対して同じ整数をEquals返さなければならないことが非常に重要です。理想的には、異なるオブジェクトは可能な限り異なるハッシュ コードを返す必要がありますが、常に可能であるとは限りません (同じハッシュ コードを持つ異なるオブジェクトは「衝突」と呼ばれます)。trueGetHashCode

キーを見つけるこの方法は、キーとして使用されるすべてのオブジェクトが適切な実装を持っていることを確認する必要がありますがGetHashCode(元のデフォルトの実装objectはめったに適切ではありません)、このアルゴリズムは * 非常に* 効率的 (効率的なハッシュ アルゴリズムを使用) であることに注意してください。何が価値があるのか​​。、または辞書のインデクサーを使用ContainsKeyすると、各キーを調べて比較するよりもはるかに高速になります。これは、Selectコードを使用しないようにするために必要なことですGetHashCode

したがって、あなたの質問に答えるために、はい、CounterForEachRelatedTagDict.Select(x => x.Key).Contains(tag.Key)インデクサーが見つけることができないアイテムを見つけることはかなり可能です。

于 2012-12-03T18:41:56.113 に答える
2

最初:ContainsKeyその Linq Query の代わりにメソッドを使用できます。

GetHashCode2 番目:とEqualsfor をオーバーライドする必要がありますMyType。これが Dictionary がキーを検索して比較する方法です。

次の同様の質問を確認してください: Dictionary.ContainsKey は False を返しますが、 Trueを返します。オブジェクトをジェネリック Dictionary キーとして使用します。

于 2012-12-03T18:37:34.747 に答える
1

GetHashCode型を辞書キーとして使用するには、との 2 つのメソッドをオーバーライドする必要がありますEquals

デフォルトでは (オーバーライドしない場合GetHashCode)、タイプのすべてのオブジェクトは (同じフィールド値であっても) 一意の値を返します。これは、辞書に入れるのとまったく同じ「参照」のみを見つけることができることを意味します。次の 2 つのタイプを検討MyType1GetHashCodeEqualsください。

class MyType1
{
  public MyType1(int id, string name) {Id = id; Name = name;}
  public int Id {get; private set;}
  public string Name {get; private set;}
}


internal class MyType2
{
    public MyType2(int id, string name)
    {
        Id = id;
        Name = name;
    }

    public int Id { get; private set; }
    public string Name { get; private set; }

    bool Equals(MyType2 other)
    {
        return Id == other.Id && string.Equals(Name, other.Name);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (ReferenceEquals(this, obj)) return true;
        if (obj.GetType() != this.GetType()) return false;
        return Equals((MyType2) obj);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            return (Id*397) ^ Name.GetHashCode();
        }
    }
}

var d1 = new Dictionary<MyType1, int>();
d1[new MyType1(1, "1")] = 1;
d1[new MyType1(1, "1")]++; // will throw withKeyNotFoundException

var d2 = new Dictionary<MyType2, int>();
d1[new MyType2(1, "1")] = 1;
d1[new MyType2(1, "1")]++; // Ok, we'll find appropriate record in dictionary
于 2012-12-03T18:47:29.837 に答える