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值基于namePerson但在我的情况下,我正在创建一个自定义collectionPerson每个place. 换句话说place将是独一无二的collection

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>Equals仅基于? 我的问题在语义方面很少。我不是在寻求解决方案,但只是知道是否对何时有意义有一般的理解?我从文档中找不到与此主题相关的任何内容。KTKeyedCollection

更新:

我发现这里提到的确切问题http://bytes.com/topic/net/answers/633980-framework-bug-keyedcollection-t

提问者向 MS 提交了错误报告。引用他的话(2007 年 4 月 18 日):

我将此作为错误提交给 Microsoft,他们已经验证并接受了它。这是问题 ID 271542,可以在此处跟踪:

“我们已经在 WinXP pro SP2 和 VSTS2005 SP1 上重现了这个错误,我们正在将此错误发送给 Visual Studio 产品团队中的适当小组进行分类和解决。”

虽然我不认为这是一个错误,但这肯定是一个烦恼。但只是想知道 MS 一开始是如何接受这个错误的(预计现在找不到该页面)。Imo,它只是考虑不周的继承模型。

4

1 回答 1

5

询问收藏似乎有两件事是有意义的:

  • 是否包含住在巴黎的名叫 Jean,以及

  • 是否包含一个住在巴黎的人

KeyedCollection<TKey, TItem> 类提供了两种方法来询问这些问题:

住在巴黎的叫 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 回答