Reputation: 11
My understanding of C# is that a subclass cannot override a parent's implementation of a method unless that method is marked virtual. If a subclass declares a method with the same name of a parent method that is not marked virtual, it simply hides that method, so that if the method is called from a reference of the parent type it will call the parent method and if it is called from a reference of the subclass type it will call the subclass method. However, I found a situation in the C# library that appears to break this behavior.
The Collection<T>
declares a method public void Add(T item)
.
This method is not virtual, so implementations in a subclass should not override its behavior. However, the following test produces a contradictory result.
public void Test()
{
ObservableCollection<String> strings1 = new ObservableCollection<String>();
strings1.CollectionChanged += OnCollectionChanged;
strings1.Add("One String");
Collection<String> strings2 = strings1;
strings2.Add("Another String");
}
public void OnCollectionChanged(Object source,
NotifyCollectionChangedEventArgs e)
{
Console.WriteLine("Collection Change!");
}
Since the NotifyCollectionChanged
behavior is not implemented in the Collection
class, and the ObservableCollection
class cannot override the Add
method of the Collection
class, I would expect a collection change event to be fired only when the object is referenced as a ObservableCollection<String>
, not when it is referenced as a Collection<String>
. But two events are fired. The result is:
Collection Change!
Collection Change!
Can anyone explain what is going on here?
Upvotes: 1
Views: 438
Reputation: 17556
ObservableCollection < T> is derived from the Collection < T > and notification event will be handled where it is assigned a handler which is defined in the ObservableCollection class , Add Method of Collection call the Insert method which is virtual and overridden in ObservableCollection class and in the overridden method its calling the event handler.
Upvotes: 0
Reputation: 12654
ObservableCollection does not have it's own Add method. Instead it relies on Collection class Add, that is:
public class Collection<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
public void Add(T item)
{
if (this.items.IsReadOnly)
ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection);
this.InsertItem(this.items.Count, item);
}
protected virtual void InsertItem(int index, T item)
{
this.items.Insert(index, item);
}
}
And InsertItem is a virtual method that is overriden in ObservableCollection.
public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged
{
protected override void InsertItem(int index, T item)
{
this.CheckReentrancy();
base.InsertItem(index, item);
this.OnPropertyChanged("Count");
this.OnPropertyChanged("Item[]");
this.OnCollectionChanged(NotifyCollectionChangedAction.Add, (object) item, index);
}
}
Upvotes: 1