在 C# 中使用弱处理程序引发 PropertyChanged 事件时发生 ExecutionEngineException

Posted

技术标签:

【中文标题】在 C# 中使用弱处理程序引发 PropertyChanged 事件时发生 ExecutionEngineException【英文标题】:ExecutionEngineException occurs while raising PropertyChanged event with weak handlers in C# 【发布时间】:2012-03-15 20:13:11 【问题描述】:

我正在尝试引发一个弱事件处理程序正在侦听的PropertyChanged 事件(通过PropertyChangedEventManager)。出于某种原因,当我提出事件时,我收到了 ExecutionEngineException。

我的事件引发代码如下:

protected virtual void RaisePropertyChanged(string aPropertyName)

    var lHandler = this.PropertyChanged;

    if (lHandler != null)
    
        // ExecutionEngineException is thrown here
        lHandler(this, new PropertyChangedEventArgs(aPropertyName));
    

    return;

我的处理代码如下:

public bool ReceiveWeakEvent(Type aManagerType, object aSender, EventArgs e)

    bool lHandled = false;

    if (aManagerType == typeof(PropertyChangedEventManager))
    
        OnPropertyChanged(aSender, e as PropertyChangedEventArgs);
    

    return lHandled;

当我搜索这个异常时,我没有得到任何有用的结果,而且异常本身不包含任何有用的信息!是什么导致了问题?

【问题讨论】:

【参考方案1】:

ExecutionEngineException when raising the PropertyChanged event 博客条目作者的道具。他完美地描述了问题和解决方案,但由于某种原因,他的页面在网络搜索结果中的排名并不高。我想在这里发布问题和答案,以帮助更多遇到相同问题的人。

如果你从ReceiveWeakEvent返回false,那么WeakEventManager会调用Environment.FailFast()。

多么阴险的错误!我同意博客条目中的一句话:

这可能是我这辈子见过的最荒谬的过度反应错误处理。

我的固定处理程序看起来像:

public bool ReceiveWeakEvent(Type aManagerType, object aSender, EventArgs e)

    bool lHandled = false;

    if (aManagerType == typeof(PropertyChangedEventManager))
    
        OnPropertyChanged(aSender, e as PropertyChangedEventArgs);
        lHandled = true;
    

    return lHandled;

【讨论】:

呵呵。有点经典,这实际上是由 Assert() 触发的。程序员肯定没有意识到这个特定的方法仍然会在发布版本中断言。您可以通过将 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\DbgJITDebugLaunchSetting 设置设置为 0x12 来获得更好的结果。 很高兴你发布了这个;我从没想过从事件处理程序返回 false 会导致 FailFast,但显然确实如此。 第一段中的链接不再可用。我已经在单独的答案中重复了内容。【参考方案2】:

已接受答案中的链接不再可用(域已失效),但仍可通过 Wayback Machine 获取信息。我将在这里重复整个帖子,感谢原作者。如果这不是正确的做法,我相信有人会纠正它......

引发 PropertyChanged 事件时的 ExecutionEngineException

由 ceiled 于 2009 年 4 月 23 日在(他们的?)“奥卡姆说”博客上发表。

如果您曾经在 .NET 中看到过 ExecutionEngineException,您就会知道这很糟糕。甚至听起来很吓人。这是 Environment.FailFast() 引发的错误——MSDN 将其描述为“在公共语言运行时的执行引擎中出现内部错误时引发的异常”。昨晚之前,我唯一一次看到它是在我生成和运行我自己的 IL 汇编代码时,我做错了一些事情,比如从堆栈中弹出太多值之类的。

但是,昨晚我在使用 PropertyChangedEventManager 订阅它之后立即在 INotifyPropertyChanged 对象上引发 PropertyChanged 事件时得到了它。我挠了挠头……我到底是怎么设法在 CLR 中造成内部错误的?我重新启动了 Visual Studio,我重新启动了我的机器,我在其他机器上尝试了它,看看它是否是我系统上某种疯狂的损坏,但它是完全可重复的。

最后,无奈之下,我设置了 .NET 源代码步进(无论如何我一直想做的事情)并再次运行它——这一次,而不是出现在我引发 PropertyChanged 事件的那一行,异常停止在 WeakEventManager.cs 中的这段代码上:


bool condition = listener.ReceiveWeakEvent(managerType, sender, args);
if (!condition)

    Invariant.Assert(condition, SR.Get("ListenerDidNotHandleEvent"), SR.Get("ListenerDidNotHandleEventDetail", new object[]  listener.GetType(), managerType ));

没错……当 ReceiveWeakEvent 返回 false(表示侦听器未处理引发的事件)时,WeakEventManager 调用 Environment.FailFast()。这相当于恐怖电影中的人们选择朝自己的脸开枪而不是变成僵尸并可能伤害他们的朋友的软件。它将一个事件写入事件查看器,显示“不可恢复的系统错误”。

这可能是我这辈子见过的最可笑的过度反应错误处理,而且出于某种原因,谷歌在这个问题上完全没有帮助。搜索“PropertyChangedEventManager ExecutionEngineException”几乎一无所获——英文的唯一结果是 404,而且由于某种原因,Google 的缓存版本中没有任何关键字。希望这能避免我在某个地方的随机事件处理程序不小心返回 false 时所经历的强烈挫败感,并被告知我的执行引擎已变得不可恢复地损坏并且将被关闭以保护自己。如果这篇文章对你有帮助,请在 cmets 中告诉我,这样我就知道我的时间并没有完全浪费。

【讨论】:

以上是关于在 C# 中使用弱处理程序引发 PropertyChanged 事件时发生 ExecutionEngineException的主要内容,如果未能解决你的问题,请参考以下文章

[C#] 学会使用异常(整理中)

如何编写 C++ 代码来处理 C# 代码中引发的事件

由C# yield return引发的思考

27.异常

过滤器生成器在 C# mongoDB 驱动程序中引发异常

C# 中的弱引用 WeakReference