Derived Type based on a property of base class

670 Views Asked by At

I have a base class and a few derived classes:

public class Item
{
    public (int itemId, string itemName)
    {
        ItemId = itemId;
        ItemName = itemName;
    }    
    public int ItemId { get; set; }
    public string ItemName { get; set; }
}

public class Weapon : Item
{
    public Weapon(int itemId, string itemName) : base(itemId, itemName) 
    {
        if(itemId != 1) throw InvalidObjectType;
    }
    //custom properties
}

public class Armor : Item
{
    public Armor(int itemId, string itemName) : base(itemId, itemName) 
    {
        if(itemId != 2) throw InvalidObjectType;
    }
    //custom properties
}
//etc

The problem is, I have a base class and the base class can be instanced, but depending on the typeId I want to force a specific class. So let's say, in the constructor of A if typeId = 0 accept base class, else throw. If typeId = 1 force to be class B otherwise throw; Is this a good approach? I want this because the type comes from the database so I can create the correct instance based on that (this will be done via a if statement of course) but I want to make sure that the code enforces that business rule. Am I approaching this in a good way? Or how can I do this. I'm using C# with EF Core (can this rule be set in the model configuration????)

EDIT:

Category(categoryId, category)
Item (id, name, categoryId, etc)
Weapon (itemId, dmg, maxenhancelevel, etc)

So depending on the category of the item returned I create a derived class or the base class (depends).

Foun the answer on how to mapping this with EF Core: https://weblogs.thinktecture.com/pawel/2018/05/entity-framework-core-inheritance-tpt-is-not-supported-is-it-part-1-code-first.html

1

There are 1 best solutions below

3
On BEST ANSWER

One approach would be to place all of your classes in a separate project and use the internal modifier on the constructors to enforce how they are generate:

public class BaseClass
{
  internal BaseClass() { }
}
public class Class1:BaseClass
{
  internal Class1() : base() { }
}

public class Class2 : BaseClass
{
  internal Class2() : base() { }
}

Then, in that same project create a static factory method to return the proper class:

public static BaseClass ClassFactory(int typeId)
{
  switch(typeId)
  {
    case 0:
      return new BaseClass();
    case 1:
      return new Class1();
    case 2:
      return new Class2();
    default:
      throw new ArgumentException("Unrecoginzed typeId");
  }
}

By using internal you prevent the creation of these classes from outside the project.