KeyedCollection是否仅在Key确定其中的项相等时才有意义?



我认为这是我们经常遇到的问题。

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是基于Personname,但在我的情况下,我正在创建一个自定义的collection,每个place只有一个Person。换句话说,placecollection中是唯一的。

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中。所以我的问题是,只有当Equals仅仅基于TK部分时,KeyedCollection<K, T>才有意义吗?我的问题与语义无关。我不是在要求解决方案,但只是知道什么时候KeyedCollection有意义吗?我在文档中找不到任何与此主题相关的内容。

更新:

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

提问者向ms提交了一个bug报告。引用他的话(日期为07年4月18日):

我把这个作为bug提交给了微软,他们已经验证过了接受它。Issue ID 271542,可以在这里追踪:

"我们在WinXP pro SP2和VSTS2005 SP1上复制了这个错误,并且我们正在发送这个错误到适当的组内的视觉Studio Product Team for分流和解决方案。"

虽然我不认为这是一个bug,但这确实是一个烦恼。但是我想知道微软是如何接受这个bug的(预期,这个页面现在找不到)。在我看来,这只是考虑得很差的继承模型。

似乎有两件事是有意义的:

  • 是否包含居住在巴黎的名为Jean的人和

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

The KeyedCollection<TKey,>类提供了恰好两个方法来询问这些问题:

  • Contains(item)方法和

  • Contains(TKey) Method

住在巴黎的人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;
}

相关内容

  • 没有找到相关文章

最新更新