C# 为什么取消订阅DataContextChanged会由于集合已修改而导致InvalidOperation异常

C# 为什么取消订阅DataContextChanged会由于集合已修改而导致InvalidOperation异常,c#,silverlight,C#,Silverlight,我最近在silverlight中偶然发现了一个使用datacontext changed事件的问题 如果您订阅了更改的事件,然后立即取消订阅,则会引发异常 DataContextChanged += MainPage_DataContextChanged; void MainPage_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { var vm = e.NewValue as VM; if

我最近在silverlight中偶然发现了一个使用datacontext changed事件的问题

如果您订阅了更改的事件,然后立即取消订阅,则会引发异常

DataContextChanged += MainPage_DataContextChanged;
void MainPage_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
  var vm = e.NewValue as VM;
  if(vm != null)
  {
     DataContextChange-= MainPage_DataContextChanged;//throws invalidoperationexception for collection modified
  }
}
为了解决这个问题,我只是在晚些时候取消订阅活动,在这种情况下,要求提前取消订阅,而不是晚些,这样就行了

DataContextChanged += MainPage_DataContextChanged;
void MainPage_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
  var vm = e.NewValue as VM;
  if(vm != null)
  {
      //forces item onto the dispatcher queue so anything needing to happen with 'collections' happens first
      Dispatcher.BeginInvoke(()=>
        {
     DataContextChange-= MainPage_DataContextChanged;//throws invalidoperationexception for collection modified
         });
  }
}
我猜集合是可视化树中所有不同控件的子元素,我猜它们的更新可能发生在调度程序队列上,所以我的问题是:

为什么在事件触发后取消订阅会影响在此之后要修改或更新的集合

编辑:
在考虑过这一点之后,这是否与在完成之前修改的事件处理程序调用列表有关?

您对修改的调用列表的怀疑是正确的

根据dotPeek的反编译,以下是触发DataContextChanged事件的代码:

private void RaisePublicDataContextChanged()
{
  if (this._dataContextChangedInfo == null)
    return;
  object oldValue = this._dataContextChangedInfo.OldValue;
  object dataContext = this.DataContext;
  if (oldValue == dataContext)
    return;
  this._dataContextChangedInfo.OldValue = dataContext;
  List<DependencyPropertyChangedEventHandler>.Enumerator enumerator = this._dataContextChangedInfo.ChangedHandlers.GetEnumerator();
  try
  {
    // ISSUE: explicit reference operation
    while (((List<DependencyPropertyChangedEventHandler>.Enumerator) @enumerator).MoveNext())
    {
      // ISSUE: explicit reference operation
      ((List<DependencyPropertyChangedEventHandler>.Enumerator) @enumerator).get_Current()((object) this, new DependencyPropertyChangedEventArgs(FrameworkElement.DataContextProperty, oldValue, dataContext));
    }
  }
  finally
  {
    enumerator.Dispose();
  }
}
private void RaisePublicDataContextChanged()
{
if(this.\u dataContextChangedInfo==null)
返回;
object oldValue=此。_dataContextChangedInfo.oldValue;
对象dataContext=this.dataContext;
if(oldValue==dataContext)
返回;
这._dataContextChangedInfo.OldValue=dataContext;
List.Enumerator Enumerator=this._dataContextChangedInfo.ChangedHandlers.GetEnumerator();
尝试
{
//问题:显式引用操作
while(((List.Enumerator)@Enumerator.MoveNext())
{
//问题:显式引用操作
((List.Enumerator)@Enumerator.get_Current()((对象)此,新的DependencyPropertyChangedEventArgs(FrameworkElement.DataContextProperty,oldValue,dataContext));
}
}
最后
{
枚举数。Dispose();
}
}

如您所见,代码使用枚举器在处理程序集合中进行迭代。因此,当您在调用处理程序期间取消订阅事件时,您正在使枚举数无效,从而导致您看到的异常。

是否收到包含该异常的消息?