一系列不同的仿制药

Chr*_*net 2 c# arrays generics inheritance invariants

简而言之,我希望能够通过在所使用的所有类型中使用父类型,在数组中使用不同类型参数来存储泛型.MSDN提到这是不可能的,因为泛型是不变的类型,但是一条评论声明自4.0框架以来这种情况发生了变化.

这是我想要做的基本示例:

    public class Animal
    {
    }
    public class Dog : Animal
    {
    }
    public class Cat : Animal
    {
    }

    public class MyGeneric<T>
    { }
    public class MyInheritedGeneric<T> : MyGeneric<T>
    { }

    static void Main(string[] args)
    {
        MyGeneric<Animal>[] myGenericArray = new MyGeneric<Animal>[] 
        {
            new MyGeneric<Dog>(),
            new MyInheritedGeneric<Cat>()
        };
    }
Run Code Online (Sandbox Code Playgroud)

这会返回类似的错误:

Cannot implicitly convert type
'InheritanceTest.Program.MyGeneric<InheritanceTest.Program.Dog>' to
'InheritanceTest.Program.MyGeneric<InheritanceTest.Program.Animal>'

Cannot implicitly convert type
'InheritanceTest.Program.MyInheritedGeneric<InheritanceTest.Program.Cat>'
to 'InheritanceTest.Program.MyGeneric<InheritanceTest.Program.Animal>'
Run Code Online (Sandbox Code Playgroud)

有没有办法使用类型的父类将泛型存储在数组中,或者这根本不可能?我真的希望有可能,否则会让我的节目成为一场噩梦......

编辑:更多背景!

我正在制作课程以在游戏中产生敌人.我称之为模板(与实际的模板类无关,我很可能称之为蓝图或工厂).敌人构造函数接受一个模板,它用它来确定自己的值.当游戏加载时,模板用于生成所有敌人,使用他们的Generate()函数,该函数返回他们被分配生成的相应类型的数组.使用模板创建的所有对象都有一个构造函数,它将模板作为唯一参数.

public class Template<T>
{
    protected static Random random = new Random(); 
    protected int _amount;

    public int Amount
    {
        get { return _amount; }
    }

    public virtual T CreateInstance()
    {
        return (T)Activator.CreateInstance(typeof(T), this);
    }
    public virtual T[] Generate()
    {
        T[] objects = new T[Amount];
        for (int i = 0; i < Amount; ++i)
            objects[i] = CreateInstance();
        return objects;
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是BasicZombie.cs文件的摘要,其中包含实际的敌人类和模板.

    class Tpl_BasicZombie : Tpl_Enemy<BasicZombie>
{
    public Tpl_BasicZombie()
    {
        _hp = 4;
        _speed = 3;
        _amount = 10;
    }
}

class BasicZombie : GroundEnemy
{
    public BasicZombie(Tpl_BasicZombie template)
        : base(template, TextureManager.Get("zombie_base"), 1, 8)
    { }

    public void StuffHappens()
    { }
}
Run Code Online (Sandbox Code Playgroud)

加载游戏时,我想通过数组中的所有模板来加载它们中的敌人.我知道我可以手动执行此操作,但每次我创建一个新类型的敌人时,我都需要手动将其添加到代码中(因此可能会忘记多次).

我的两个选择是:1-使用通用,然后出现上述问题.2-使用非泛型,并将类型存储在里面,这将锚定返回类型Generate()函数.这意味着生成函数将输出一个对象数组,每次模板生成一个敌人数组时,需要将其转换为合适的类型.

我脑子里有一个空间,告诉我这一切都有一个优雅的解决方案,我希望它是对的!

Jon*_*eet 6

是的,C#4支持通用变体 - 但仅限于接口和委托的声明,因此在这种情况下您将无法执行此操作.当然你可以创建一个界面:

public interface IGeneric<out T>
Run Code Online (Sandbox Code Playgroud)

然后在你的类中实现它,此时你可以创建一个IGeneric<Animal>.

如果您可以提供有关您要实现的目标的更多详细信息,我们可以帮助您找到替代方法.


Tim*_* S. 1

除了 Jon Skeet 的信息之外,您也许可以执行以下操作:

public MyGeneric<T2> ToOtherType<T2>()
{
    if (typeof(T2).IsAssignableFrom(typeof(T)))
    {
        // todo: get the object
        return null;
    }
    else
        throw new ArgumentException();
}

        new MyGeneric<Dog>().ToOtherType<Animal>(),
        new MyInheritedGeneric<Cat>().ToOtherType<Animal>()
Run Code Online (Sandbox Code Playgroud)