c#中的方法覆盖/隐藏行为

本文关键字:隐藏 覆盖 方法 | 更新日期: 2023-09-27 18:04:18

我对c#的理解是,子类不能覆盖父类方法的实现,除非该方法被标记为virtual。如果一个子类声明了一个与父方法同名的方法,且该方法不是标记为virtual,则它只是隐藏该方法,因此,如果从父类型的引用调用该方法,它将调用父方法,如果从子类类型的引用调用该方法,它将调用子类方法。然而,我在c#库中发现了一种情况,似乎打破了这种行为。

Collection<T>声明一个方法public void Add(T item)。这个方法不是虚拟的,所以子类中的实现不应该覆盖它的行为。然而,下面的测试产生了一个矛盾的结果。

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!");
}

由于NotifyCollectionChanged行为没有在Collection类中实现,并且ObservableCollection类不能覆盖Collection类的Add方法,我希望只有当对象被引用为ObservableCollection<String>时才会触发集合更改事件,而不是当它被引用为Collection<String>时。但是触发了两个事件。结果是:

Collection Change!
Collection Change!
谁能解释一下这是怎么回事?

c#中的方法覆盖/隐藏行为

ObservableCollection没有自己的Add方法。相反,它依赖于集合类Add,即:

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);
     }     
  }

InsertItem是一个虚方法,在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);
    }
}

ObservableCollection 派生自集合和通知事件将在它被分配一个在ObservableCollection类中定义的处理程序时进行处理,Collection的Add方法调用Insert方法,该方法是虚拟的,在ObservableCollection类中被覆盖,在被覆盖的方法中调用事件处理程序