0

I need to 2 levels of inheritance and abstraction in master-child relationship is the beginning of of the discussion.

What I want is to make sure all inherited objects from BaseMaster must have a list of children, and the type of the children must inherit from BaseChild. According to that post I have settled my design to

public abstract class BaseMaster<TChild> where TChild : BaseChild
{
    public Collection<TChild> Children { get; }
}

public abstract BaseChild
{ }

public class FirstRealMaster : BaseMaster<FirstRealChild> { /* add more properties */ }

public class FirstChild : BaseChild { /* add more properties */ }

But with such design I lost the ability to use base object type to describe inherited objects, because BaseMaster<BaseChild> b = new FirstRealMaster(); won't be allowed, technically there are different types. Following is a sample code I hope I can make it work.

    static BaseMaster<BaseChild> ReturnBaseMaster(int i)
    {
        if (i == 1)
        {
            return new FirstRealMaster();
        }
        else if (i == 2)
        {
            return new SecondRealMaster();
        }

        return null;
    }

Such limitation caused lots of inconvenience. Any suggestion here how to improve the design to achieve my goal that I need object model to enforce all inherited classes to have children. And meanwhile I still want the flexibility to use base type for inherited types?

hardywang
  • 4,864
  • 11
  • 65
  • 101
  • It's a bit hard to come to a design solution when we don't know how these classes are supposed to work together. Couldn't you do something like "BaseMaster b = new FirstRealMaster();" – Clay07g Jul 07 '17 at 18:01
  • Please check my updated post. – hardywang Jul 07 '17 at 19:16
  • Why can't you just return `IMaster`? Without implementation of `child` and `master` I don't know what do you want to achieve. – apocalypse Jul 07 '17 at 19:30
  • It looks like there is some difference between 4.5.2 and 4.0. Your code complies and run in 4.5.2. But after I convert it to 4.0 and replace IReadOnlyList with IList I got exactly the same error I have. – hardywang Jul 07 '17 at 20:00
  • It's about `out` generic modifier in `IReadOnlyList`. https://stackoverflow.com/questions/10956993/out-t-vs-t-in-generics – apocalypse Jul 07 '17 at 20:05
  • I guess I figured it Covariance and Contravariance, but it also looks like only very limited interface https://msdn.microsoft.com/library/dd799517(VS.100).aspx#InterfaceCovariantTypeParameters is supported in .Net 4.0 – hardywang Jul 07 '17 at 20:14

1 Answers1

1

I am not sure what are you asking for, but maybe this will fit your expectations:

using System.Collections.Generic;

namespace ConsoleApplication
{
    class Program
    {
        static void Main (string[] args)
        {
            IMaster<IChild>           master1 = new ConcreteMaster ();
            IMaster<BaseChild>        master2 = new ConcreteMaster ();
            IMaster<ConcreteChild>    master3 = new ConcreteMaster ();
            BaseMaster<ConcreteChild> master4 = new ConcreteMaster ();
        }
    }

    public interface IChild { }

    public interface IMaster<out T> where T : IChild
    {
        IReadOnlyList<T> Children { get; }
    }

    public abstract class BaseMaster<T> : IMaster<T> where T : IChild
    {
        private readonly List<T> children = new List<T> ();

        public IReadOnlyList<T> Children => children;

        public void Add (T child)
        {
            children.Add (child);
        }
    }

    public abstract class BaseChild : IChild { }

    public class ConcreteMaster : BaseMaster<ConcreteChild> { }

    public class ConcreteChild : BaseChild {  }
}

Notice if you want add child, you need to use base type.

apocalypse
  • 5,764
  • 9
  • 47
  • 95