how to specify that MyMethod will return IList of T where T can be anything that inherits from A or instances of A itself ?
You don't have to
You can just declare that it returns IList<A>
. Why? Becase - given that B
inherits from A
- every item of B
can be passed where the requiered type is A
.
Call it polymorphism by inheritance, Liskov substitution principle, or method variance, the name doesn't matter. What matters is that the following works (tested on LinqPad):
public class A {}
public class B: A {}
public IList<A> MyMethod()
{
var result = new List<A>();
//add some items to result
result.Add(new B());
return result;
}
Genetic alternatives
In fact, you can tell that you are going to return a IList<TA>
and request a few derived types (TB
, TC
...) to populate it with. That's right, the following example also works (tested on LinqPad):
void Main()
{
MyMethod<A, B, C>();
}
public class A {}
public class B: A {}
public class C: A {}
public IList<TA> MyMethod<TA, TB, TC>()
where TB : TA, new()
where TC : TA, new()
where TA : class
{
var result = new List<TA>();
//add some items to result
result.Add(new B() as TA);
result.Add(new C() as TA);
return result;
}
Or if you want to keep a particular base type (say you want to return an IList<A>
but it actually contains items of classes that derive from A
, then you can do this:
void Main()
{
MyMethod<B, C>();
}
public class A {}
public class B: A {}
public class C: A {}
public IList<A> MyMethod<T1, T2>()
where T1 : A, new()
where T2 : A, new()
{
var result = new List<A>();
//add some items to result
result.Add(new T1() as A);
result.Add(new T2() as A);
return result;
}
You don't have to, but you can
OK, if you really want to say it returns IList<T>
where T : A
. Then say that!
void Main()
{
MyMethod<B>();
}
public class A {}
public class B: A {}
//public class C: A {} //Even if I don't add that class
public IList<T> MyMethod<T>()
where T : A, new()
{
var result = new List<T>();
//add some items to result
result.Add(new T());
return result;
}
Yes, that one cannot return a mix of item of type T
and items of type A
, because it says it returns IList<T>
and not every item of type A
is also an item of type T
.
What happens with your code
Look at your code:
public IList<A> MyMethod(){
IList<B> result = new List<B>();
//add some items to result
return result;
}
You are trying to return an IList<B>
when you said that you was going to return an IList<A>
. Let's suppose that that works... then what would happen to the caller of your method? Let's see:
public class A {}
public class B: A {}
public class C: A {}
void Main()
{
//Hmmm... I need a IList<T>, let's call MyMethod!
IList<A> list = MyMethod();
//Cool, I got an IList<A>, now let's add some items...
var item = new C();
//Well, item is of type C...
// and C inherits from A, so I must be able to add it...
list.Add(item); //BOOM!
//It was actually an IList<B>!
// and C doesn't dervive from B, so you can't add it.
}
DFTBA!