In C#, are event handler arguments contravariant?
If I have a class that raises an event, with (e.g.) FrobbingEventArgs, am I allowed to handle it with a method that takes EventArgs?
Here's some code:
class Program
{
static void Main(string[] args)
{
Frobber frobber = new Frobber();
frobber.Frobbing += FrobberOnFrobbing;
frobber.Frob();
}
private static void FrobberOnFrobbing(object sender,
EventArgs e)
{
// Do something interesting. Note that the parameter is 'EventArgs'.
}
}
internal class Frobber
{
public event EventHandler<FrobbingEventArgs> Frobbing;
public event EventHandler<FrobbedEventArgs> Frobbed;
public void Frob()
{
OnFrobbing();
// Frob.
OnFrobbed();
}
private void OnFrobbing()
{
var handler = Frobbing;
if (handler != null)
handler(this, new FrobbingEventArgs());
}
private void OnFrobbed()
{
var 开发者_JAVA百科handler = Frobbed;
if (handler != null)
handler(this, new FrobbedEventArgs());
}
}
internal class FrobbedEventArgs : EventArgs { }
internal class FrobbingEventArgs : EventArgs { }
The reason I ask is that ReSharper seems to have a problem with (what looks like) the equivalent in XAML, and I'm wondering if it's a bug in ReSharper, or a mistake in my understanding of C#.
Maybe covariant's not the word
Close. The word you are looking for is contravariant. Conversion of a method group to a delegate type is covariant in return type and contravariant in formal parameter types.
Here's my blog article on the subject:
https://learn.microsoft.com/en-us/archive/blogs/ericlippert/covariance-and-contravariance-in-c-part-three-method-group-conversion-variance
if I have a class that raises an event, with (e.g.) FrobbingEventArgs, am I allowed to handle it with a method that takes EventArgs?
Well, you tried it and it worked, so clearly yes. For the justification in the specification see the section helpfully entitled "Method group conversions".
Yes you can but when you access the e parameter in the event handler you will only be able to access the members that belong to EventArgs base class unless you cast it as the derived type. I think the word is polymorphic rather than covariant and all classes in c# are pollymorphic, it is a language feature.
Since events can only be invoked from within the class that declared them, your derived class cannot directly invoke events declared within the base class.
You can achieve what you want by creating a protected invoking method for the event. By calling this invoking method, your derived class can invoke the event.
For even more flexibility, the invoking method is often declared as virtual, which allows the derived class to override it. This allows the derived class to intercept the events that the base class is invoking, possibly doing its own processing of them.
You can do:
protected void OnFrobbing(EventArgs e)
{
var handler = Frobbing;
if (handler != null)
handler(this, new e);
}
Or:
protected virtual void OnFrobbing(EventArgs e)
{
var handler = Frobbing;
if (handler != null)
handler(this, new e);
}
精彩评论