我认为这是我们遇到的一个常见问题。
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}},但就我而言,我正在创建一个只有一个的自定义Person
每collection
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,它刚刚想到的继承模型。
答案 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;
}