我有一个从List派生的自定义类,其中Add方法仅在满足某个条件时才会添加。
我是否还需要覆盖* AddRange,或者AddRange是否只是在给定范围的每个元素上调用Add?
*:是的,new
隐藏而不是覆盖C#的上下文。
答案 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
由于您只需要验证已添加的项目而不是要删除的项目,因此您只需要覆盖InsertItem
和SetItem
。
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);