0

I am practicing in OOP and I have created a simple console application where I have 3 factions and every faction must have it's own Army, and every distinct army can contain certain units.

I used interfaces and inheritance, but I have some problem in generic conversions. I can't figure out how to solve this problem in a right way, please help me.

Here is the code.

This is my Army and Units implementation.

public abstract class Unit<T> : IUnit<T> where T : Faction {
    public string UnitName { get; set; }
    public IFaction Nation { get; set; }

    public Unit(string name) {
        UnitName = name;
    }

    public virtual void PrintUnitInfo() {
        Console.WriteLine($"UnitName: {UnitName}\nNation: {Nation}\n");
    }
}

public interface IUnit<T> where T : IFaction {
    string UnitName { get; set; }
    IFaction Nation { get; set; }

    void PrintUnitInfo();
}

public class Army<T> where T : IFaction {
    private List<IUnit<T>> units = new List<IUnit<T>>();

    public void Recruit(IUnit<T> unit) {
        units.Add(unit);
    }

    public void PrintFactionName() {
        Console.WriteLine(nameof(IFaction));
    }

}

And here is the Faction implementation.

public abstract class Faction : IFaction {
    public string Name { get; }
    public int Minerals { get; set; }
    public Army<Faction> Army { get; set; }

    public Faction(string name, Army<Faction> army) {
        Name = name;
        Minerals = 100;
        Army = army;
    }

    public virtual void Greetings() {
        Console.WriteLine("Printing FucntionInfo from BaseFaction");
    }

    public virtual void PrintUnitsInfo() {
        Console.WriteLine("Printing UnitsInfo from BaseFaction");
    }

}

public interface IFaction {

    string Name { get; }
    Army<Faction> Army { get; set; }
    int Minerals { get; set; }

    void Greetings();
    void PrintUnitsInfo();

}

And finally here is the usage the where compiler shows an error:

Cannot convert from 'Army<Zerg>' to 'Army<Faction>".

public static void Main(string[] args) {

        Faction zerg = new Zerg("Zerg", new Army<Zerg>());


        zerg.Army.PrintFactionName();

        Console.ReadKey();

    }

}

public class Zerg : Faction {

    public Zerg(string name, Army<Faction> army) : base(name, army) { }

}

Sorry if question looks very big and confusing, but I can't make my problem clear in other way.

mjwills
  • 23,389
  • 6
  • 40
  • 63
Chestera
  • 667
  • 2
  • 13
  • 22
  • 1
    Please, post code of the main, not an image! You never use `T` in `IUnit`and in `Unit` nor in the rest of the code you provided. So it is useless to use generics... –  Oct 05 '19 at 11:51
  • But how can I specify the faction of an certain army without generics? Okay I'll edit it – Chestera Oct 05 '19 at 11:54
  • Try to do a diagram of your hierarchy like using UML or just by using a paper and a pencil to draw rectangles and lines. You will see the flaws of your design. –  Oct 05 '19 at 12:03
  • I have tryed but, on every try I am unable to achieve what i want – Chestera Oct 05 '19 at 12:05

1 Answers1

2

You never use T in IUnit<T> and in Unit<T> nor in the rest of the code you provided. So it is useless to use generics...

So you can simply write:

static void Test()
{
  Faction zerg = new Zerg("Zerg", new Army());
  zerg.Army.Recruit(new Zealot("Zealot"));
  Console.ReadKey();
}

public interface IUnit
{
  string UnitName { get; set; }
  IFaction Nation { get; set; }

  void PrintUnitInfo();
}

abstract public class Unit : IUnit
{
  public string UnitName { get; set; }
  public IFaction Nation { get; set; }

  public Unit(string name)
  {
    UnitName = name;
  }

  public virtual void PrintUnitInfo()
  {
    Console.WriteLine($"UnitName: {UnitName}\nNation: {Nation}\n");
  }
}

public interface IFaction
{
  Army Army { get; set; }
  string Name { get; }
  int Minerals { get; set; }

  void Greetings();
  void PrintUnitsInfo();
}

public abstract class Faction : IFaction
{
  public string Name { get; }
  public int Minerals { get; set; }
  public Army Army { get; set; }

  public Faction(string name, Army army)
  {
    Name = name;
    Minerals = 100;
    Army = army;
  }

  public virtual void Greetings()
  {
    Console.WriteLine("Printing FucntionInfo from BaseFaction");
  }

  public virtual void PrintUnitsInfo()
  {
    Console.WriteLine("Printing UnitsInfo from BaseFaction");
  }
}

public class Army
{
  private List<IUnit> units = new List<IUnit>();

  public void Recruit(IUnit unit)
  {
    units.Add(unit);
  }

  public void PrintFactionName()
  {
    Console.WriteLine(nameof(IFaction));
  }
}

public class Zerg : Faction
{
  public Zerg(string name, Army army) : base(name, army) { }
}

public class Zealot : Unit
{
  public Zealot(string name) : base(name) { }
}

Now if you want to use generics to do some things I don't understand, you may refine your design by sketching a simple drawing using a paper, a pencil and rectangles with lines or you can use UML.

UML Tutorial

And there is one question to ask to you: why use interfaces?

To answer this question, ask: the code I write to define the interfaces, I use it for doing what?

It is the same for generics.

What is the difference between an interface and a class, and why I should use an interface when I can implement the methods directly in the class?

C# Generics Level 1
C# Generics Level 2
Generics in .NET

  • Let me make things more clear. everything is fine in this code, also in my code which i posted above, but there is one problem. for example if i create Zealot which is Prottos unit and I have Zerg object, than i can add zealot in zergs army, and only thing i wanna do is that when i write zerg.army.recruit(new Zealot()) compiler should return an error at that time and restrict me to doing that – Chestera Oct 05 '19 at 12:12
  • zealot is fighter unit, which must be included in Army's list – Chestera Oct 05 '19 at 12:17
  • You can. Answer updated. Try to make a drawing with a paper and a pencil and draw rectangles and lines to link them. –  Oct 05 '19 at 12:18
  • Without using UML, it can be as simple as this: [paper-and-pencil-design](http://www.ordisoftware.com/files/stack-overflow/Chestera-Army.png). I highly recommend learning UML. –  Oct 05 '19 at 12:26