派生类设计问题(多态)

时间:2011-08-27 15:02:02

标签: c# polymorphism

设计问题如下,实际问题包括2个模块。

模块1类(外部装配)

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; }
}

模块2类

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 
    }
}

本质上派生的类在模块2中生成,并在外部装配模块1中处理,在/ c引用丢失。

是将模块2的派生类对象转换为模块1类对象的唯一方法

我希望我已经清楚地解释了这个问题,如果不是我道歉,我会非常感谢这方面的解决方案。

1 个答案:

答案 0 :(得分:0)

如果我正确理解您的问题,您希望将IList<LetterSmallA>视为IList<LetterA>。这在C#中是不可能的,并且有很好的理由:IList<LetterA>所说的可能之一就是“尝试向其添加任何LetterAIList<LetterSmallA>无法做到这一点,因此没有内置的方法来做你想做的事。

您可以做的是创建自己的IList<T>实现,该实现包含另一个IList<T>派生类型:

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
}

class约束不是必需的,但可以使代码更简单。)

ALetters的setter可能如下所示:

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