要明确:如果您只需要观察标准功能,您应该使用ObservableCollection(T) 或其他现有类。永远不要重建你已经拥有的东西。
..但是..如果你需要特殊事件并且必须更深入,你不应该从 List 派生!如果您从 List 派生,则不能重载 Add() 以查看每个添加。
例子:
public class MyList<T> : List<T>
{
public void Add(T item) // Will show us compiler-warning, because we hide the base-mothod which still is accessible!
{
throw new Exception();
}
}
public static void Main(string[] args)
{
MyList<int> myList = new MyList<int>(); // Create a List which throws exception when calling "Add()"
List<int> list = myList; // implicit Cast to Base-class, but still the same object
list.Add(1); // Will NOT throw the Exception!
myList.Add(1); // Will throw the Exception!
}
不允许覆盖Add(),因为您可能会破坏基类 (Liskov substitution principle) 的功能。
但一如既往,我们需要让它发挥作用。但是如果你想建立自己的列表,你应该通过实现一个接口来实现它:IList<T>。
实现前后添加事件的示例:
public class MyList<T> : IList<T>
{
private List<T> _list = new List<T>();
public event EventHandler BeforeAdd;
public event EventHandler AfterAdd;
public void Add(T item)
{
// Here we can do what ever we want, buffering multiple events etc..
BeforeAdd?.Invoke(this, null);
_list.Add(item);
AfterAdd?.Invoke(this, null);
}
#region Forwarding to List<T>
public T this[int index] { get => _list[index]; set => _list[index] = value; }
public int Count => _list.Count;
public bool IsReadOnly => false;
public void Clear() => _list.Clear();
public bool Contains(T item) => _list.Contains(item);
public void CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _list.GetEnumerator();
public int IndexOf(T item) => _list.IndexOf(item);
public void Insert(int index, T item) => _list.Insert(index, item);
public bool Remove(T item) => _list.Remove(item);
public void RemoveAt(int index) => _list.RemoveAt(index);
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
#endregion
}
现在我们已经拥有了我们想要的所有方法,并且不需要实现太多。我们代码的主要变化是,我们的变量将是IList<T>,而不是List<T>、ObservableCollection<T> 或其他任何东西。
现在大惊喜:所有这些都实现了IList<T>:
IList<int> list1 = new ObservableCollection<int>();
IList<int> list2 = new List<int>();
IList<int> list3 = new int[10];
IList<int> list4 = new MyList<int>();
这将我们带到下一点:使用接口而不是类。你的代码不应该依赖于实现细节!