2

これは私たちが遭遇する一般的な問題だと思います。

class Person
{
    public string place;
    public string name;

    public Person(string place, string name)
    {
        this.place = place;
        this.name = name;
    }

    public bool Equals(Person other)
    {
        if (ReferenceEquals(null, other))
            return false;

        return name == other.name;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as Person);
    }

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

    public override string ToString()
    {
        return place + " - " + name;
    }
}

このクラスがあるとします。KeyedCollection次のように実装できます。

class Collection : KeyedCollection<string, Person>
{
    protected override string GetKeyForItem(Person item)
    {
        return item.place;
    }
}

ここでは、デフォルトEqualsは に基づいてnameいますPersonが、私の場合はごとcollectionに 1 つだけのカスタムを作成しています。つまり、 で一意になります。Personplaceplacecollection

Person p1 = new Person("Paris", "Paul");
Person p2 = new Person("Dubai", "Ali");

var collection = new Collection { p1, p2 };
var p3 = new Person("Paris", "Jean");
if (!collection.Contains(p3))
    collection.Add(p3);   // explosion

私は問題を理解しています。オーバーContains(Person)ロードは、重複キー例外を引き起こす可能性がある内部ディクショナリに値を追加しCollection<T>.Contains(T)ながら、値ベースの線形検索を行うものです。Add(Person)ここで、等式が に基づいてplaceいれば、この問題は存在しなかったでしょう。

回避策があります:

class Collection : KeyedCollection<string, Person>
{
    protected override string GetKeyForItem(Person item)
    {
        return item.place;
    }

    new public bool Contains(Person item)
    {
        return this.Contains(GetKeyForItem(item));
    }
}

しかし、これもまた、一般的なことを行う場合を意味します

var p3 = new Person("Paris", "Jean");
bool b = collection.Contains(p3); //true

を返しますtrueが、実際にはまだJean存在しcollectionません。だから私の質問は、の一部だけに基づいているKeyedCollection<K, T>場合にのみ意味がありますか? 私の質問はセマンティクス側ではほとんどありません。私は解決策を求めているわけではありませんが、いつ意味があるかについて一般的な理解があることを知っているだけですか? ドキュメントから、この件に関連するものは見つかりませんでした。EqualsKTKeyedCollection

アップデート:

ここで言及されている正確な問題を見つけましたhttp://bytes.com/topic/net/answers/633980-framework-bug-keyedcollection-t

質問者がバグレポートを MS に提出した場所。彼の言葉を引用すると (2007 年 4 月 18 日付け):

私はこれをバグとして Microsoft に提出しましたが、Microsoft はそれを確認して受け入れました。これは問題 ID 271542 で、次の場所で追跡できます

「WinXP pro SP2 および VSTS2005 SP1 でこのバグを再現しました。このバグを Visual Studio 製品チーム内の適切なグループに送信して、トリアージと解決を図っています。」

これはバグではないと思いますが、これは確かに迷惑です。しかし、そもそも MS がこれをバグとしてどのように受け入れたのか疑問に思っています (おそらく、ページは現在見つかりません)。Imo、その継承モデルはよく考えられていません。

4

1 に答える 1

5

コレクションに尋ねることが理にかなっていることが 2 つあります。

  • パリに住むジャンという人物が含まれているかどうか、および

  • パリに住んでいる人が含まれているかどうか。

KeyedCollection <TKey, TItem> クラスは、これらの質問をするための正確に 2 つのメソッドを提供します。

パリに住む Jean という名前人物は、パリに住む Paul という名前人物( Person.Equals )と同じではありません。しかし、パリに住んでいる人がいる場合、あなたの規則によれば、パリに住んでいる別の人がいるはずがありません。

したがって、基本的に、新しい人物を追加する前に、コレクションに正しい質問をする必要があります。

if (!collection.Contains(p3.place))
    collection.Add(p3);

便宜上、TryAdd メソッドをクラスに追加すると人物が正常に追加された場合、またはコレクション内に同じ場所に住んでいる人物が既に存在する場合に返されます。

public bool TryAdd(Person person)
{
    if (Contains(GetKeyForItem(person)))
        return false;
    Add(person);
    return true;
}
于 2013-04-13T03:38:19.813 に答える