Why was EventArgs constraint dropped from EventHandler<TEventArgs>?
Asked Answered
A

0

0

In .NET Framework 2.0, delegate EventHandler got its generic generalization that allowed the second argument to be not only of type EventArgs, but also of a derived type, imposing a stricter constraint on its implementations. But somewhen in .NET Framework 4, likely in .NET Framework 4.5, the generic constraint was removed, according to a comment I found both in reference source and .NET Runtime source.

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System
{
    public delegate void EventHandler(object? sender, EventArgs e);

    public delegate void EventHandler<TEventArgs>(object? sender, TEventArgs e); // Removed TEventArgs constraint post-.NET 4
}

But what was the point in dropping the constraint and thus breaking the compatibility with extant users? Or, to make this answerable even by someone outside the .NET team, what could be such a motivation?

I came across this archaic change due to SonarQube rule S3906, which looks like a copy of the deprecated CA1009 and requires that the event handler's type requires EventArgs as its second argument. This is now in conflict with CA1003, which requires the use of the generic EventArgs<TEventArgs>. I chose to suppress the issue via EditorConfig as I cannot change the quality profile in SonarQube, but I am still left wondering why this breaking change was needed in the first place.

I've seen a very similar question asked before as part of a great question regarding EventHandler<TEventArgs> variance and also in a separate question but my question was not answered there. Their question is about why the constraint is not there (current state), I am asking about why it was removed (reason for change), which feels a bit different because the reason needs to be strong enough to justify the change.

Augsburg answered 31/5, 2021 at 18:44 Comment(2)
I don't get why it breaks anything: if a handler has the signature void (object, EventArgs) it can still be passed to the constructor of the generic EventArgs<TEventArgs>, the only thing that breaks is that void (object, object) now compiles where it did not beforeLombroso
I was thinking about binary compatibility and a situation when a binary calls the event handler with e.g. EventArgs.Empty and after the change to the definition of EventHandler<TEventArgs>, it is no longer guaranteed that EventArgs.Empty is a valid value. But now that I gave it a bit more thought, I cannot come up with a scenario when this backfires. :-( It's quite late here and I had a rough day, will need to think about that more in the morning.Augsburg

© 2022 - 2024 — McMap. All rights reserved.