KeyedCollection仅在Key确定其中项目的相等性时才有意义吗?

时间:2013-04-13 02:56:34

标签: c# semantics equality keyedcollection

我认为这是我们遇到的一个常见问题。

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的{​​{1}},但就我而言,我正在创建一个只有一个的自定义Personcollection Person。换句话说,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的{​​{1}}部分时才有意义吗?我的问题在语义方面很少。 我不是要求解决方案,但只是知道对K何时有意义有一般性的了解?我在文档中找不到与此主题相关的任何内容。

更新

我发现了http://bytes.com/topic/net/answers/633980-framework-bug-keyedcollection-t

中提到的确切问题

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

  

我将此作为错误提交给Microsoft,他们已经验证了它   接受了它。它的问题ID为271542,可以跟踪here

     

“我们在WinXP专业版SP2和VSTS2005 SP1上重现了这个错误   我们将此错误发送到Visual中的相应组   Studio产品团队进行分类和解决。“

虽然我不认为这是一个错误,但这肯定是一个烦恼。但只是想知道MS如何首先接受这个作为一个错误(预计,现在无法找到页面)。 Imo,它刚刚想到的继承模型。

1 个答案:

答案 0 :(得分:4)

要问收藏品似乎有两件事是有道理的:

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

  • 是否包含 a 居住在巴黎的人

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

居住在巴黎的名为Jean的人 的人不是同一个人保罗住在巴黎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;
}