开发者

Derived class design problem (Polymorphism)

The design problem is as follows, actual problem consists of 2 modules.

Module 1 classes (External Assembly)

abstract class Letter
{
    private int _id;
    protected Letter(int id) { _id = id; }

    public abstract string Val { get; }
}

class LetterA : Letter
{
    public LetterA(int id) : base(id) {}

    public override string Val
    {
        get { return "A"; }
    }
}

class WordWithALettersOnly
{
    public IList<LetterA> ALetters { get; set; }
}开发者_开发百科

Module 2 classes

class LetterSmallA : LetterA 
{
    public LetterSmallA(int id) : base(id) {}
    public override string Val
    {
        get { return "a"; }
    }
}

class WordWithSmallALettersOnly : WordWithALettersOnly
{
    private IList<LetterSmallA> _aLetters;
    public new IList<LetterSmallA> ALetters
    {
        get { return _aLetters; }
        set
        {
            _aLetters = value;
            if(_aLetters != null)
                base.ALetters = value.Cast<LetterA>().ToList(); // <-- reference lost
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        var smallAWordOnly = new WordwithSmallALettersOnly();
        smallAWordOnly.ALetters = new List<LetterSmallA>(){new LetterSmallA(1)};
        Console.WriteLine("d : " + smallAWordOnly.ALetters.Count); // --> 1
        Console.WriteLine("b : " + ((WordwithALettersOnly)smallAWordOnly).ALetters.Count); // --> 1
        smallAWordOnly.ALetters.Add(new LetterSmallA(2)); --> 2
        Console.WriteLine("d : " + smallAWordOnly.ALetters.Count);
        Console.WriteLine("b : " + ((WordwithALettersOnly)smallAWordOnly).ALetters.Count); // -> 1 
    }
}

Essentially derived classes are generated in the module 2 and processed in the external assembly module 1, on a/c reference loss.

Is the only way to translate the derived class objects of the module 2 to module 1 class objects

I hope i have been explain clearly the issue, if not i do apologise, would really appreciate solutions to this.


If I understand your question correctly, what you want is to treat IList<LetterSmallA> as IList<LetterA>. This is not possible in C# and for very good reasons: one of the things IList<LetterA> says is possible to do with is is to “try to add any LetterA to it. This is not possible with IList<LetterSmallA> and so there is no built-in way to do what you want.

What you can do is to create your own implementation of IList<T> that wraps another IList<T> of derived type:

class BaseTypeList<TBase, TDerived> : IList<TBase>
    where TBase : class
    where TDerived : class, TBase 
{
    private readonly IList<TDerived> m_derivedList;

    public BaseTypeList(IList<TDerived> derivedList)
    {
        m_derivedList = derivedList;
    }

    public IEnumerator<TBase> GetEnumerator()
    {
        return m_derivedList.Cast<TBase>().GetEnumerator();
    }

    public void Add(TBase item)
    {
        var derivedItem = item as TDerived;
        if (derivedItem == null)
            throw new ArgumentException();
        m_derivedList.Add(derivedItem);
    }

    public void Clear()
    {
        m_derivedList.Clear();
    }

    // other members implemented in a similar fashion
}

(The class constraints are not necessary, but make some code simpler.)

Your setter for ALetters could then look like this:

_aLetters = value;
if(_aLetters == null)
    base.ALetters = null;
else
    base.ALetters = new BaseTypeList<LetterA, LetterSmallA>(value);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜