ObservableCollection事件中的神秘代表算术实现

时间:2013-10-04 09:45:30

标签: .net events delegates

正在做一些ObservableCollection实现的研究我发现了一些我无法理解的代码。 这是由.Net Reflector反编译的代码片段:

[NonSerialized]
private NotifyCollectionChangedEventHandler CollectionChanged;
[NonSerialized]
private PropertyChangedEventHandler PropertyChanged;

event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
  add
  {
    this.PropertyChanged += value;
  }
  remove
  {
    this.PropertyChanged -= value;
  }
}

public virtual event NotifyCollectionChangedEventHandler CollectionChanged
{
  add
  {
    NotifyCollectionChangedEventHandler changedEventHandler = this.CollectionChanged;
    NotifyCollectionChangedEventHandler comparand;
    do
    {
      comparand = changedEventHandler;
      changedEventHandler = Interlocked.CompareExchange<NotifyCollectionChangedEventHandler>(ref this.CollectionChanged, comparand + value, comparand);
    }
    while (changedEventHandler != comparand);
  }
  remove
  {
    NotifyCollectionChangedEventHandler changedEventHandler = this.CollectionChanged;
    NotifyCollectionChangedEventHandler comparand;
    do
    {
      comparand = changedEventHandler;
      changedEventHandler = Interlocked.CompareExchange<NotifyCollectionChangedEventHandler>(ref this.CollectionChanged, comparand - value, comparand);
    }
    while (changedEventHandler != comparand);
  }
}

protected virtual event PropertyChangedEventHandler PropertyChanged
{
  add
  {
    PropertyChangedEventHandler changedEventHandler = this.PropertyChanged;
    PropertyChangedEventHandler comparand;
    do
    {
      comparand = changedEventHandler;
      changedEventHandler = Interlocked.CompareExchange<PropertyChangedEventHandler>(ref this.PropertyChanged, comparand + value, comparand);
    }
    while (changedEventHandler != comparand);
  }
  remove
  {
    PropertyChangedEventHandler changedEventHandler = this.PropertyChanged;
    PropertyChangedEventHandler comparand;
    do
    {
      comparand = changedEventHandler;
      changedEventHandler = Interlocked.CompareExchange<PropertyChangedEventHandler>(ref this.PropertyChanged, comparand - value, comparand);
    }
    while (changedEventHandler != comparand);
  }
}

我无法理解的是为什么PropertyChanged有两个(公共和私有)实现,但只有一个(受保护的)CollectonChanged? 那个代表算术在do-while循环中的目的是什么?为什么不像PropertyChanged的私有实现那样只是“this.Property + = value”?

1 个答案:

答案 0 :(得分:1)

避免使用反编译器查看框架代码,使用可以从Reference Source获取的实际源代码。此类的源位于Source.NET 4.5 \ 4.6.0.0 \ net \ fx \ src \ CompMod \ System \ Collections \ ObjectModel \ ObservableCollection.cs目录中。然后,您将看到CollectionChanged事件真正的样子:

    //------------------------------------------------------
    /// <summary>
    /// Occurs when the collection changes, either by adding or removing an item.
    /// </summary>
    /// <remarks>
    /// see <seealso cref="INotifyCollectionChanged"/>
    /// </remarks>
    [field:NonSerializedAttribute()]
    public virtual event NotifyCollectionChangedEventHandler CollectionChanged;

就是这样,没有更多的代码。

反编译器不够智能,无法识别C#编译器为实现事件而生成的自动生成的代码,因此不知道如何将其折叠回真正的 C#代码事件。至少部分原因是这种缺陷在.NET 4.0中发生了变化。 do-while循环是新的,它可以确保事件订阅线程安全。较旧的方法使用[MethodImpl(MethodImplOptions.Synchronized)]属性使其成为线程安全的。它有一个缺陷,它会锁定这个,这种做法可能导致无意的死锁。

是的,有两个PropertyChanged事件。一个是INotifyPropertyChanged的显式实现,它只使用另一个。这样做是为了确保事件不是公共的,就像您继承接口时通常会发生的那样,它被重新声明为 protected