Um es klar zu sagen: Wenn Sie nur die Standardfunktionalitäten beachten müssen, sollten Sie die ObservableCollection(T) oder andere bestehende Klassen. Bauen Sie niemals etwas nach, was Sie bereits haben.
Aber: Wenn Sie besondere Ereignisse brauchen und tiefer gehen müssen, sollten Sie nicht von List ableiten! Wenn Sie von List ableiten, können Sie nicht überladen Add()
um jede Anzeige zu sehen.
Ejemplo:
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!
}
Es darf nicht überschrieben werden Add()
, da man die Funktionen der Basisklasse ( Liskov-Substitutionsprinzip ).
Aber wie immer müssen wir dafür sorgen, dass es funktioniert. Wenn Sie jedoch Ihre eigene Liste erstellen möchten, sollten Sie dies durch die Implementierung der Schnittstelle tun: IList<T>
.
Beispiel, das ein Before- und After-Add-Ereignis implementiert:
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
}
Jetzt haben wir alle Methoden, die wir wollen, und mussten nicht viel implementieren. Die wichtigste Änderung in unserem Code ist, dass unsere Variablen nun IList<T>
代わりに List<T>
, ObservableCollection<T>
oder was auch immer.
Und jetzt das große Aha-Erlebnis: All diese Geräte 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>();
Das bringt uns zum nächsten Punkt: Verwenden Sie Schnittstellen anstelle von Klassen. Ihr Code sollte niemals von Implementierungsdetails abhängen!