5

我有一个从 List 派生的自定义类,它带有一个 Add 方法,该方法仅在满足特定条件时才添加。

我是否还需要覆盖* AddRange,或者 AddRange 是否只是在给定范围的每个元素上调用 Add?

*:是的,在 C# 的上下文new隐藏而不是覆盖。

4

3 回答 3

9

如果要创建自定义集合。不要List<T>Collection<T>或直接实现IList<T>or派生它ICollection<T>。事实上,类中的Add方法List<T>不是虚拟的。

注意:List<T>.AddRange使用Array.Copy.

更新

继承 Collection 时,您只需覆盖 2 个方法!

public class MyCollection : Collection<string>
{
    private bool IsValidItem(string item)
    {
        return; // Your condition : true if valid; false, otherwise.
    }

    // This method will be called when you call MyCollection.Add or MyCollection.Insert
    protected override void InsertItem(int index, string item)
    {
        if(IsValidItem(item))
            base.InsertItem(index, item);
    }

    // This method will be called when you call MyCollection[index] = newItem
    protected override void SetItem(int index, string item)
    {
        if(IsValidItem(item))
            base.SetItem(index, item);
    }
}

如果您要验证的项目没有在上面的代码中string替换string为正确的类型。

于 2013-02-03T16:03:22.077 回答
4

不要使用改变方法语义的隐藏。这真是糟糕的设计。

创建一个实现IList<T>. 最简单的方法是继承自Collection<T>. Collection<T>以方法的形式实现IList<T>并具有四个扩展点protected virtual

InsertItem
SetItem
RemoveItem
ClearItems

由于您只需要验证添加的项目而不是删除的项目,因此您只需覆盖InsertItemSetItem.

class MyCollection:Collection<T>
{
    private void ValidateItem(T item)
    {
       if(item is invalid)
         throw new ArgumentException("Item is invalid");
    }

    protected override InsertItem(int index, T item)
    {
        ValidateItem(item);
        base.InsertItem(index, item);
    }

    protected override SetItem(int index, T item)
    {
        ValidateItem(item);
        base.SetItem(index, item);
    }
}
于 2013-02-03T16:17:20.133 回答
2

如果您需要一个行为与 a 完全相同的集合List<T>,除了仅添加有效对象之外,我不会创建自定义集合。

只要清楚扩展程序在做什么,请改用扩展程序并调用它们AddIfValid(T value)或您喜欢的任何名称。AddRangeIfValid(IEnumerable<T>)

这是一个例子:

public static void AddIfValid(this List<T> list, T value)
{
    if (/* check if value is valid here */)
        list.Add(value);
}

一旦你定义了你的扩展,像这样使用它:

myList.AddIfValid(myValue);
于 2013-02-03T16:10:33.313 回答