public abstract class SomeBaseClass {}
public class SomeSpecificClass: SomeBaseClass {
public int propertyA;
public string propertyB;
}
public delegate void Callback<T>(T data);
public class Foo {
void MethodA <T> (Callback<T> theInstance) where T: SomeBaseClass {
MethodB(theInstance);
}
void MethodB(Callback<SomeBaseClass> theInstance) {
}
void MethodC() {
Callback<SomeSpecificClass> cb = (data) => {};
MethodA(cb);
}
void MethodD <T> (T theInstance) where T: SomeBaseClass {
MethodE(theInstance);
}
void MethodE (SomeBaseClass theInstance) {
}
}
Produces the error in MethodA
:
Argument 1: cannot convert from 'Callback<T>' to 'Callback<SomeBaseClass>' [Assembly-CSharp]
Callback<T> theInstance
But MethodD works fine passing its instance to MethodE
Why can't I pass the generic Callback<T>
instance in MethodA to argument of type Callback<SomeBaseClass>
in MethodB when I'm specifiying the constraint that T extends SomeBaseClass
Basically, you can't do this because it's not safe.
Suppose we have a concrete class derived from SomeBaseClass
:
public class SomeOtherSpecificClass {}
Suppose we change your MethodB
to:
void MethodB(Callback<SomeBaseClass> theInstance)
{
theInstance(new SomeOtherSpecificClass());
}
That should compile, right? After all, you're just passing a SomeOtherSpecificClass
into a Callback<SomeBaseClass>
, which should be fine.
Then if I call MethodA
like this:
Callback<SomeSpecificClass> callbcak = data => Console.WriteLine(data.propertyA);
MethodA(callback);
... then if all of that were allowed, we'd be passing a SomeOtherSpecificClass
into a delegate expecting a SomeSpecificClass
.
Your MethodD
and MethodE
examples are fine, because MethodE
can only use members of SomeBaseClass
... but a Callback<SomeSpecificClass>
really requires a SomeSpecificClass
, so you can't just treat it as if it were a method accepting a SomebaseClass
.
To show this more simply:
// This is valid...
string text = "";
object obj = text;
// This isn't...
Action<string> stringAction = text => Console.WriteLine(text.Length);
Action<object> objectAction = stringAction;
// ... because it would allow this:
objectAction(new object());
See more on this question at Stackoverflow