List.AddRange是否调用List.Add?

时间:2013-02-03 16:01:19

标签: c# .net list

我有一个从List派生的自定义类,其中Add方法仅在满足某个条件时才会添加。

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

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

3 个答案:

答案 0 :(得分:9)

如果要创建自定义集合。不要从List<T>派生,而是从Collection<T>派生,或直接实施IList<T>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

答案 1 :(得分: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);
    }
}

答案 2 :(得分:2)

如果您需要一个行为与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);