C# Randomize inherited class 没有硬编码

C# Randomize inherited class without hardcoding

我想要实现的是通过派生名称 class 或枚举名称生成一个随机派生 class。虽然我的代码在这种情况下有效,但如果我决定扩展它,它将需要大量的硬编码,对我来说这似乎是一个糟糕的解决方案。

这是我的示例代码:(UnitTypes 变量包含所有派生的 class 动态名称,所以我觉得它可能有用 - 但我可以弄清楚如何使用。)

public void Run()
        {

            var UnitTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.BaseType == typeof(Unit));
            Unit NewMonster = new Unit(); //<---

        konny: //for testing things out.

            int RandomType = new Random().Next(0, UnitTypes.Count());

            switch (RandomType)
            {
                case 0:
                    NewMonster = new Dingo();
                    break;
                case 1:
                    NewMonster = new Buffalo();
                    break;
                case 2:
                    NewMonster = new Dog();
                    break;
            }
            Console.WriteLine($"A wild {NewMonster.Name} appears");
            NewMonster.Attack();
            Console.ReadLine();

            goto konny;            
        }

为了示例,Baseclass + 1 派生。

    public class Unit
    {
        public Enemies Name { get; set; }

        public enum Enemies
        {
            Dingo, Buffalo, Dog
        }

        public virtual void Attack()
        {
            //nothing to see here
        }
   
    }

    class Dingo : Unit
    {

        public Dingo()
        {
            Name = Enemies.Dingo;
        }

        public override void Attack()
        {
            Console.WriteLine($"{Name}  gnaws at your brain");
        }

    }

这样的事情怎么样。首先创建一个基地class(我不知道你为什么把它命名为Unit,我把我的命名为BaseAnimal):

namespace AnimalsTest
{
    public abstract class BaseAnimal
    {    
        public enum EnemiesTypes
        {
            Dingo, Buffalo, Dog
        }

        public abstract IEnumerable<EnemiesTypes> Enemies { get; }

        public abstract void Attack();
    }
}

请注意,它是一个 abstract(不可实例化)并且任何子 classes 都需要实现一个 Enemies 属性 getter 和Attack 方法。

然后我创建了三个子classes(在同一个命名空间):

class Dingo : BaseAnimal
{
    public override IEnumerable<EnemiesTypes> Enemies =>
        new List<EnemiesTypes> { EnemiesTypes.Buffalo, EnemiesTypes.Dog };

    public override void Attack()
    {
        Console.WriteLine($"{nameof(Dingo)} Gnaws at your brain");
    }
}

class Buffalo : BaseAnimal
{
    public override IEnumerable<EnemiesTypes> Enemies =>
        new List<EnemiesTypes> { EnemiesTypes.Dog };

    public override void Attack()
    {
        Console.WriteLine($"{nameof(Buffalo)} Runs you down");
    }
}

class Dog : BaseAnimal
{
    public override IEnumerable<EnemiesTypes> Enemies =>
        new List<EnemiesTypes> { EnemiesTypes.Buffalo };

    public override void Attack()
    {
        Console.WriteLine($"{nameof(Dog)} Barks at you");
    }
}

这些都非常简单class,你可以把它们变得更复杂。

最后一个测试例程,可以锻炼我认为你想要的东西。我从 enum 的值中获取 classes 的名称并随意实例化它们。

private static readonly Random Random = new Random();
public static void Test()
{
    var animalClasses = Enum.GetNames(typeof(EnemiesTypes)).Select(n => n.ToString()).ToArray();
    var thisAssembly = Assembly.GetExecutingAssembly().FullName;

    for (var i = 0; i < 6; ++i)
    {
        var className = nameof(AnimalsTest) + "." + animalClasses[Random.Next(0, animalClasses.Length)];
        var animal = (BaseAnimal) Activator.CreateInstance(thisAssembly, className).Unwrap();
        animal.Attack();
        Console.WriteLine($"{animal.GetType().Name} has enemies: {string.Join(", ",animal.Enemies.Select(e=>e.ToString()))}");
        Console.WriteLine();
        ;
    }
}

请注意,测试代码不知道它正在使用的 classes 的名称,它全部从枚举的值中提取。

每次我运行这个,我得到不同的结果(因为,嗯,Random)。但是,这是典型的 运行:

的输出
Buffalo Runs you down
Buffalo has enemies: Dog

Dog Barks at you
Dog has enemies: Buffalo

Buffalo Runs you down
Buffalo has enemies: Dog

Dog Barks at you
Dog has enemies: Buffalo

Dingo Gnaws at your brain
Dingo has enemies: Buffalo, Dog

Dingo Gnaws at your brain
Dingo has enemies: Buffalo, Dog