Search code examples
c#inotifypropertychangedweak-referencesexecutionengineexception

ExecutionEngineException occurs while raising PropertyChanged event with weak handlers in C#


I'm trying to raise a PropertyChanged event that is being listened to by a weak event handler (via PropertyChangedEventManager). For some reason I'm getting an ExecutionEngineException when I raise the event.

My event raising code looks like:

protected virtual void RaisePropertyChanged(string aPropertyName)
{
    var lHandler = this.PropertyChanged;

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

    return;
}

My handling code looks like:

public bool ReceiveWeakEvent(Type aManagerType, object aSender, EventArgs e)
{
    bool lHandled = false;

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

    return lHandled;
}

I'm not getting any useful results when I search for this exception, and the exception itself doesn't contain any useful information! What's causing the problem?


Solution

  • Props to the author of the ExecutionEngineException when raising the PropertyChanged event blog entry. He describes the problem and solution perfectly, but for some reason his page doesn't appear very high in web search results. I wanted to post the question and answer here to help out more people who encounter the same issue.

    So it turns out that WeakEventManager will call Environment.FailFast() if you return false from ReceiveWeakEvent.

    What an insidious bug! I agree with a quote from the blog entry:

    This may be the most ridiculously over-reactive error processing I've ever seen in my life.

    My fixed handler looks like:

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