3

假设我有这样的课程:

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>来存储值,并使用字典内置功能在添加或删除之前检查键。通过包装内部字典值来实现接口的所有方法

我很感激你对我的案子的看法。

PS:我希望列表中的元素很少(<100 项)。性能不会是问题

编辑:我正在使用.Net 3.5 SP1。

Edit2:根据乔恩的建议,这是我的实现:

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

    }
}
4

1 回答 1

2

HashSet<MyClass>非常适合您的用例,因为它可以模拟您的意图并且可以使用自定义进行配置IEqualityComparer<MyClass>(因此不MyClass实现并不重要IEquatable<MyClass>)。

不幸HashSet的是没有实现IList,所以它不能直接进行基于索引的访问——但你真的需要吗?也许可以通过重新考虑您的业务逻辑的某些部分来放宽这个要求?

于 2012-07-05T08:30:39.357 回答