假设我有一个这样的课程:
public class MyClass {
public int Id { get; set;}
public string Name { get; set; }
}
请注意,在我的情况下,这个类失控(来自第三方库)并且没有实现相等比较器。
现在我想拥有一些这样的项目,允许我根据索引删除项目。
我期待能够做到:
void Foo()
{
var collection = new MyClassCollection();
var a = new MyClass { Id = 1, Name = "A" };
var b = new MyClass { Id = 2, Name = "B" };
collection.Add(a);
collection.Add(b);
// Other instance, that can come from external code
var otherA = new MyClass { Id = 1, Name = "A" };
var otherB = new MyClass { Id = 2, Name = "B" };
collection.Remove(otherA);
Console.WriteLine(collection.Count); // should output 1
Console.WriteLine(collection.Contains(otherB)); // should be true
collection.Add(otherB); //
Console.WriteLine(collection.Count); // should still output 1
}
实际上,在集合中搜索时只应考虑ID。此代码是依赖序列化DTO的项目的一部分,因此不能依赖实例。
我应该如何实现MyClassCollection?
我想到了两种可能性,但对我来说看起来都不优雅:
List<MyClass>
并添加新方法。这将使.Add和.Remove保持原样,并可能导致消费者代码的麻烦ICollection<MyClass>
的类。创建内部Dictionary<int, MyClass>
以存储值,并使用字典内置功能在添加或删除之前检查密钥。通过包装内部字典值我很感激你对我案子的观点。
PS:我希望列表中的元素很少(&lt; 100项)。性能不会成为问题
编辑:我正在使用.Net 3.5 SP1。
Edit2:根据Jon的建议,这是我的实现:
public class MyClassCollection : HashSet<MyClass>
{
private class MyClassIDComparer : IEqualityComparer<MyClass>{
public bool Equals(MyClass x, MyClass y)
{
if (x == null && y == null) return true;
else if (x == null || y == null) return false;
else return x.ID == y.ID;
}
public int GetHashCode(MyClass obj)
{
return obj.ID.GetHashCode();
}
}
public MyClassCollection() : base(new MyClassIDComparer())
{
}
}
答案 0 :(得分:2)
HashSet<MyClass>
非常适合您的使用案例,因为它可以为您的意图建模,并且可以使用自定义IEqualityComparer<MyClass>
进行配置(因此MyClass
无法实现{无关紧要{ {1}})。
不幸的是IEquatable<MyClass>
没有实现HashSet
,所以它不能直接进行基于索引的访问 - 但你真的需要它吗?也许通过重新思考业务逻辑的某些部分可以放宽这一要求?