正确的方法来实现依赖于对象子属性的自定义集合?

时间:2012-07-05 08:26:10

标签: c# collections

假设我有一个这样的课程:

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?

我想到了两种可能性,但对我来说看起来都不优雅:

  1. 继承自List<MyClass>并添加新方法。这将使.Add和.Remove保持原样,并可能导致消费者代码的麻烦
  2. 创建一个实现ICollection<MyClass>的类。创建内部Dictionary<int, MyClass>以存储值,并使用字典内置功能在添加或删除之前检查密钥。通过包装内部字典值
  3. 来实现接口的所有方法

    我很感激你对我案子的观点。

    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())
        {
    
        }
    }
    

1 个答案:

答案 0 :(得分:2)

HashSet<MyClass>非常适合您的使用案例,因为它可以为您的意图建模,并且可以使用自定义IEqualityComparer<MyClass>进行配置(因此MyClass无法实现{无关紧要{ {1}})。

不幸的是IEquatable<MyClass>没有实现HashSet,所以它不能直接进行基于索引的访问 - 但你真的需要它吗?也许通过重新思考业务逻辑的某些部分可以放宽这一要求?