I’ve been trying to create a generic event. Basically it should look like this:
namespace DelegateTest
{
class Program
{
static void Main(string[] args)
{
var lol = new SomeClass();
lol.SomeEvent += handler;
}
static void handler(object sender, SomeDerivedClass e)
{
}
}
class SomeClass
{
public delegate void SomeEventDelegate<in T>(object sender, T data);
public event SomeEventDelegate<ISomeInterface> SomeEvent;
}
interface ISomeInterface
{
}
class SomeDerivedClass : ISomeInterface
{
}
}
I want to allow the user to pass any delegate which’s second parameter is derived from “ISomeInterface.”
“in” specifies contra-variance, right? That means if the API is expecting something more general, you can pass it something more specific (in my base “ISomeInterface” would be general, and my “SomeDerivedClass” would be specific.)
I am, however, being told my the compiler that “no overload for method handler matches DelegateTest.SomeClass.SomeEventDelegate.”
I am wondering why this isn’t working. What are the problems that would be caused if it was? Or am I missing something for it to work?
Thanks in advance!
Yes.
No. Delegate contravariance allows a delegate to reference a method with parameter types that are less derived than in the delegate type. For example, suppose
ISomeInterfacehad a base interface:And suppose
handlertookISomeBaseInterfaceinstead ofSomeDerivedClass:Then
new SomeClass().SomeEvent += handlerwould work.Here’s why the original code isn’t type safe: When
SomeClassraisesSomeEvent, it can potentially pass anything that implementsISomeInterfaceas thedataargument. For example, it could pass an instance ofSomeDerivedClass, but it could also pass an instance ofIf you were able to register
void handler(object sender, SomeDerivedClass e)with the event, that handler would wind up being invoked withSomeOtherDerivedClass, which doesn’t work.In summary, you can register event handlers that are more general than the event type, not event handlers that are more specific.
UPDATE: You commented:
I don’t think C# lets you declare an
eventthat works with arbitrary delegate types. Here’s how you can write methods that add event handlers and invoke them: