问题
I have an abstract class Creature that takes a generic type argument, extended by two other classes Human and Spider. Each subclass defines the generic type of its parent.
I am stuck with how to pass a subclass as a reference of parent class to a method.
public interface IDamagable
{
void OnSimpleHit();
}
public interface IStabAble : IDamagable
{
void OnKnifeStab();
}
public interface ISlapAble : IDamagable
{
void OnSlap();
}
public abstract class Creature<T> where T : IDamagable
{
public abstract void Init(T damageListener);
}
public abstract class Human : Creature<ISlapAble>
{
}
public abstract class Spider : Creature<IStabAble>
{
}
public class MainClass
{
public void Test()
{
List<Spider> spiderList = new List<Spider>();
List<Human> humanList = new List<Human>();
PrintList<IDamagable>(spiderList); // Argument `#1' cannot convert
//`System.Collections.Generic.List<newAd.B_A_A>' expression
//to type `System.Collections.Generic.List<newAd.A_A<newAd.I_B>>'
}
protected void PrintList<T>(List<Creature<T>> list)
{
}
}
This doesnt throw error if PrintList took 2 generic arguments
protected void PrintList<T,U>(List<T> list) where T : Creature<U> where U : IDamagable
{
}
But then I don't want to pass U again, as T was already constructed with U as type parameter, e.g Spider already defined Creature to take type parameter of IStabAble.
So basically, I'm stuck with how to write the method such that it caters both Spider and Human with minimal number of generic parameters.
Thanks
回答1:
I am assuming that PrintList
only requires read-only forward-only access to the list.
The solution is to make the PrintList
method accept an IEnumerable<Creature<T>>
like this:
void PrintList<T>(IEnumerable<Creature<T>> list) where T: IDamagable
{
//...
}
And call it like this:
PrintList(spiderList);
Because the generic type parameter T
in IEnumerable<T>
is covariant, this will work.
In your special case, because you are using .NET 2.0 (which does not support covariant type parameters) this solution will not work. Here is a workaround:
Create a Cast
method that can convert between enumerables with different item types like this (in .NET 3.5, we already have such method as an extension method):
public static IEnumerable<U> Cast<T, U>(IEnumerable<T> source) where T : U
{
foreach (var item in source)
{
yield return item;
}
}
And use it like this:
PrintList(Cast<Spider, Creature<IStabAble>>(spiderList));
来源:https://stackoverflow.com/questions/37296664/avoid-passing-generic-type-parameter-of-class-extending-generic-class