List.AddRange是否调用List.Add

本文关键字:List Add 调用 是否 AddRange | 更新日期: 2023-09-27 17:57:38

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

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

*:是的,new隐藏,并且在C#上下文中不重写。

List.AddRange是否调用List.Add

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

注: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替换为正确的类型。

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

创建一个实现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);
    }
}

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

请使用Extensions,并将其称为AddIfValid(T value)AddRangeIfValid(IEnumerable<T>)或任何您喜欢的名称,只要清楚Extension的作用即可。

这里有一个例子:

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

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

myList.AddIfValid(myValue);