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);
精彩评论