Consider the following code:
abstract class Foo<T>
where T : Foo<T>, new()
{
void Test()
{
if(Bar != null)
Bar(this);
}
public event Bar<T> Bar;
}
delegate void Bar<T>(T foo)
where T : Foo<T>, new();
The line Bar(this)
results in the following compiler Error:
Argument type Foo<T> is not assignable to parameter type T
T is constrained to Foo<T> as I want derived classes to basically tell the base class their type, so that the type can be used in the event callback in order to save the implementor from having to cast the callback argument to the derived type.
I can see the code doesn't quite work but I'm having a bit of a blockage as to how to do this correctly without ending up with a generic delegate that can be used for any old thing. I'm also not quite sure why the T constraint doesn't create a compiler error considering it seems to be recursive.
EDIT
I need to clarify this I think! Here's a new example which, I hope will be much clearer. Note below that the OnDuckReady
event handler below generates a compiler error.
How do I get the event to pass in the correct type?
abstract class Animal<T>
where T : Animal<T>, new()
{
void Test()
{
if(AnimalReady != null)
AnimalReady(this);
}
public event AnimalHandler<T> AnimalReady;
}
delegate void AnimalHandler<T>(Animal<T> animal)
where T : Animal<T>, new();
class Duck : Animal<Duck>
{
public void FlyAway()
{
}
}
class Test
{
void Main()
{
Duck duck = new Duck();
duck.AnimalReady += OnDuckReady; // COMPILER ERROR
}
void OnDuckReady(Duck duck)
{
duck.FlyAway();
}
}
You can cast 'this' to T:
Bar((T)this);
This however will fail if you have the following:
public class MyFoo : Foo<MyFoo> { }
public class MyOtherFoo : Foo<MyFoo> { }
Because 'MyOtherFoo' is not an instance of 'MyFoo'. Take a look at this post by Eric Lippert, one of the designers of C#.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With