避免传递扩展泛型类的类的泛型类型参数



我有一个抽象类Creature,它接受一个泛型类型参数,由另外两个类Human和Spider扩展。每个子类定义其父类的泛型类型。

我一直纠结于如何将子类作为父类的引用传递给方法。

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)
    {
    }
}

如果PrintList采用2个通用参数,则不会引发错误

protected void PrintList<T,U>(List<T> list) where T : Creature<U> where U : IDamagable
    {
    }

但我不想再传递U了,因为t已经用U作为类型参数构建了,例如Spider已经定义了Creature来接受IStabAble的类型参数。

因此,基本上,我一直在思考如何编写该方法,使其能够用最少的泛型参数满足Spider和Human的需求
感谢

我假设PrintList只需要对列表的只读前向访问。

解决方案是让PrintList方法接受这样的IEnumerable<Creature<T>>

void PrintList<T>(IEnumerable<Creature<T>> list) where T: IDamagable
{
    //...
}

这样称呼它:

PrintList(spiderList);

因为IEnumerable<T>中的泛型类型参数T是协变的,所以这将起作用。

在您的特殊情况下,因为您使用的是.NET 2.0(不支持协变类型参数),所以此解决方案将不起作用。这里有一个变通方法:

创建一个Cast方法,它可以在具有不同项类型的枚举之间进行转换,如下所示(在.NET 3.5中,我们已经有了这样的方法作为扩展方法):

public static IEnumerable<U> Cast<T, U>(IEnumerable<T> source) where T : U
{
    foreach (var item in source)
    {
        yield return item;
    }
}

并像这样使用:

PrintList(Cast<Spider, Creature<IStabAble>>(spiderList));

最新更新