Inheriting different concrete realisations of an abstract class

Viewed 132

There is a basic abstract class Subj:

public abstract class Subj
{
    public IName name;
    public string ID { get; set; }
    //other members of the class
}

It has 2 derived classes: Company and Person:

public class Company : Subj
{
    //realise interface IName
    public new  IName name = new NameCompany();
}

public class Person : Subj
{
    //realise interface IName
    public new IName name = new NamePerson();
}

There is also Client class that expand functionality of Subj

public class Client : Subj
{
    //Client functionality
    //Gets folder name for a client
    public string foldername()
    {
    }
    //The list of Legal cases
    private List<LCase> _cases = new List<LCase> { };
}

The problem is, Subj must be realised as either Company or Person and then it may or may not be "expanded" into Client, which brings me to inheriting Client from Company and Person, but multiple inheritance is prohibited, how do I solve this problem?

1 Answers

The problem is not related to multiple inheritence that mix ancestors.

Using composition and generic might solve the problem, but because generic parameter constraint does not allow the OR operator yet, you can check the type in the constructor to throw a design exception at runtime.

Here is a hack:

public class Client<T> where T : Subj, new()
{
  readonly T Item = new T();
  public Client()
  {
    var type = typeof(T);
    if ( type != typeof(Person) && type != typeof(Company) )
    {
      string msg = "Generic type parameter for Client must be Person or Company."
                 + Environment.NewLine
                 + type.Name + " provided.";
      throw new TypeAccessException(msg);
    }
  }
}

You can refactor that to use a list of allowed types.

You should be able to use an interface design, but that will complicate things and reduce the typing you want if I understood the question correctly.

If all Subj childs are allowed, no need to check the type.

Usage:

public class OtherSubj : Subj
{
}

var clientPerson = new Client<Person>();    // ok
var clientCompany = new Client<Company>();  // ok
var clientOther = new Client<OtherSubj>();  // exception

You can also create classes:

public class ClientPerson : Client<Person>
{
}

public class ClientCompany : Client<Company>
{
}

You can either publish the compound instance and name it what you want:

public readonly T Item = new T();

Or offer properties and methods wrappers:

private readonly T Item = new T();

public IName name 
{ 
  get => Item.name;
  set => Item.name = value;
}
Related