Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Generic EventHandler Contravariant #5665

Closed
TylerBrinkley opened this issue Apr 20, 2016 · 6 comments
Closed

Make Generic EventHandler Contravariant #5665

TylerBrinkley opened this issue Apr 20, 2016 · 6 comments
Labels
area-System.Runtime question Answer questions and provide assistance, not an issue with source code or documentation.

Comments

@TylerBrinkley
Copy link
Contributor

Is there any reason the generic EventHandler delegate was not made contravariant? As opposed to creating my own custom EventHandler delegate it would be much better if I could just use the built-in one for my use case listed below.

public abstract class Foo
{
    public event EventHandler<FooEventArgs> FooEvent
    {
        add
        {
            FooEventAddOrRemove(value, true);
        }
        remove
        {
            FooEventAddOrRemove(value, false);
        }
    }

    protected abstract void FooEventAddOrRemove(EventHandler<FooEventArgs> handler, bool toAdd);
}

public sealed class Foo<T> : Foo
{
    public new event EventHandler<FooEventArgs<T>> FooEvent;

    protected override void FooEventAddOrRemove(EventHandler<FooEventArgs> handler, bool toAdd)
    {
        if (toAdd)
        {
            FooEvent += handler; // Compile error, Cannot implicitly convert type 'System.EventHandler<FooEventArgs>' to 'System.EventHandler<FooEventArgs<T>>'
        }
        else
        {
            FooEvent -= handler; // Compile error, Cannot implicitly convert type 'System.EventHandler<FooEventArgs>' to 'System.EventHandler<FooEventArgs<T>>'
        }
    }
}

public abstract class FooEventArgs : EventArgs
{
    public object Value => GetValue();

    protected abstract object GetValue();
}

public sealed class FooEventArgs<T> : FooEventArgs
{
    public new T Value { get; set; }

    protected override object GetValue() => Value;
}
@JanEggers
Copy link

JanEggers commented Apr 22, 2016

this cant work,

when raising the event in Foo you pass FooEventArgs.

but all handlers you register in Foo<T>require FooEventArgs<T>

if u flip inheritance it can work, remove eventhandler in Foo and derive Foo from Foo<object>
`

@TylerBrinkley
Copy link
Contributor Author

TylerBrinkley commented Apr 23, 2016

If you swap EventHandler with ContravariantEventHandler as defined below this works just fine. Events can only be raised in the defining type or nested types. Since Foo only specifies the add and remove event handler operations this is entirely legal.

public delegate void ContravariantEventHandler<in TEventArgs>(object sender, TEventArgs e);

@TylerBrinkley
Copy link
Contributor Author

TylerBrinkley commented May 28, 2016

After poking around on StackOverflow I found this question which seems to imply that it was originally made contravariant but there were issues internally related to combining multi-cast delegates. Does anyone know if this is still an issue?

http://stackoverflow.com/questions/1120688/event-and-delegate-contravariance-in-net-4-0-and-c-sharp-4-0

@iskiselev
Copy link

I believe #4556 is root cause for this restriction.

@msftgits msftgits transferred this issue from dotnet/coreclr Jan 30, 2020
@msftgits msftgits added this to the Future milestone Jan 30, 2020
@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 26, 2020
@joperezr joperezr removed the untriaged New issue has not been triaged by the area owner label Jul 1, 2020
Copy link
Contributor

Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.

This process is part of our issue cleanup automation.

@dotnet-policy-service dotnet-policy-service bot added backlog-cleanup-candidate An inactive issue that has been marked for automated closure. no-recent-activity labels Jan 1, 2025
Copy link
Contributor

This issue will now be closed since it had been marked no-recent-activity but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.

@dotnet-policy-service dotnet-policy-service bot removed this from the Future milestone Jan 15, 2025
@github-actions github-actions bot locked and limited conversation to collaborators Feb 14, 2025
@dotnet-policy-service dotnet-policy-service bot removed no-recent-activity backlog-cleanup-candidate An inactive issue that has been marked for automated closure. labels Feb 14, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Runtime question Answer questions and provide assistance, not an issue with source code or documentation.
Projects
None yet
Development

No branches or pull requests

6 participants