What I want to achieve is to by either name of derived class or enum name generate a random derived class. While my code works in this case, it will require a lot of hardcoding if i decide to expand on it and to me it seems like a bad solution.
Here is my example code: (the UnitTypes variable includes all derived class names dynamically, so i feel like it may be useful - but I could figure out how to.)
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;
}
And the Baseclass + 1 derived for sake of example.
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");
}
}
How about something like this. First create a base class (I have no idea why you named it Unit
, I named mine BaseAnimal):
namespace AnimalsTest
{
public abstract class BaseAnimal
{
public enum EnemiesTypes
{
Dingo, Buffalo, Dog
}
public abstract IEnumerable<EnemiesTypes> Enemies { get; }
public abstract void Attack();
}
}
Note that it's an abstract
(non-instantiable) and that any sub-classes need to implement an Enemies
property getter and an Attack
method.
Then I created three subclasses (in the same namespace):
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");
}
}
These are very simple classes, you could make them more complicated.
Finally a test routine that exercises what I think you want. I get the names of the classes from the values of an enum
and instantiate them at will.
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();
;
}
}
Note that the test code has no clue about the names of the classes it's working with, it pulls it all from the values of the enum.
Each time I run this, I get a different result (because of, well, Random
). But, here's the output of a typical run:
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