Tech Off Thread

9 posts

Generic Type Casting - Unsolveable?

Back to Forum: Tech Off
  • BenDi

    Hello,

    I have run on a problem and cant seem to find a way out of it.

    Basically, I need to do for generic collections what

    DerivedType[] DT = new DerivedType[10];
    BaseType[] BT = DT as BaseType[];

     
    does for arrays: to cast the generic type down in the hierarchy. It struck me as a bit odd that List<DerivedType> is not convertible to List<BaseType>, so I started to investigate. Let me give an example:

    public class A
    {
    ...
    }

    public class BusinessLogic
    {
       public static void FillList(SomeListClass<A> L)
       {
       ...
       }
    }

    // and in another component:
    public class B : A
    {
    ...
    }

    public class CallingCode
    {
       public static SomeListClass<B> GetList()
       {
         // create a list of Bs
         // call BusinessLogic.FillList
         // return list
       }
    }

    The catch is that I want the core business logic to output lists that are conveniently typed in the (dynamicly determined) fitting type of the business objects. Since the core logic does not yet know about those types and they are dynamically assigned, it can only work on Lists of 'A'.

    There is no way around this, I have to be able to create a list of As from a list of Bs. But of course it's not possible to just copy the list or even perform an array cast at the low level because the core logic adds a lot of objects (extending the list) and they should be dynamically seen in the original list of Bs. All I need to do is to 'reinterpret' the list of Bs as a list of As.

    It would be no problem to design a list from ground up to support this, but I have spent some time thinking about it and cant see any solution, so Im happy about any thoughts you might have.

    B.

  • Manip

    I doubt anyone will be able to help you unless you re-write the question so it makes a lick of sense.... And is actually correctly formatted.

  • BenDi

    What is wrong with the formatting? If I can make anything clearer I'd be happy to answer a question, but I'm pretty sure it makes sense this way.

  • Eric Falsken

    Makes sense to me. DerivedType[] can be cast to BaseType[], but List<DerivedType> can't be cast to List<BaseType> even though it should be able to, if I remember from what I read about generics.

  • draza

    I don't think you quite understand the difference between non-generic and generic case.
    List<A> has no (inheritance) relationship to List<B> regardless of (inheritance) relationship between A and B.

    However, if I understand your reasoning, the motive would be to invoke some behavior on the type contained in the list regardless of what is in the list.
    If that is the case, you can (and should) refactor that behavior into an interface (let's call it C) and then derive A and B from C. Further, you should always use a List<C>.

    Alternatively, you can use a common base class C instead of an interface.

  • ScanIAm

    And even further, it seems that this would be misunderstanding the inheritance.  If class B inherits from class A, that doesn't mean a list of class B inherits from a list of class A.

    What you really should do is implement an interface that both class A and class B can have in common.  Then you can manipulate the objects through the interface.

    I used to hate interfaces, but now that you can't have multiple inheritance, I've been force to use them.  They aren't so bad and they can solve problems like this.

    Sca

    Edit: Draza beat me to it (by about an hour...)

  • BenDi

    Thanks for the feedback so far. You're right that an interface would solve it if it was about modifying the Bs.

    But the truth is that the core logic doesn't really care about anything B implements. It only wants to create the business objects (dynamically creating Bs, but working with them as As) and put them into the list.

    The calling component however knows that it does not just get any list from the core but a list of Bs, so it thinks it should be possible to actually get a typed list of Bs back from the core.

    I realize that this is more of a convenience issue, but isn't generic typing all about preventing coding errors through type safety? If I get a list of As back and only I know that they are all Bs, that doesn't measure up to that safety.

    BTW: What really puzzles me about all that business is that Array implicitely has this functionality (B[] is not really derived from A[], but still the 'as' operator works) - while it seems to be impossible to replicate this behaviour in my own code.

  • Maurits

    You could create another constructer for List<A> that takes a List<B> as an argument... start with an empty list, and add each element of the List<B> as an A

  • bartj

    How about this:

    public class BusinessLogic
    {
       public static void FillList<T>(SomeListClass<T> L) where T : A
       {
       ...
       }
    }

    or you can use the fact that System.Collections.Generic.List<> implements System.Collections.IList:

    public class BusinessLogic
    {
       public static void FillList(IList L)
       {
       ...
       }
    }

    IList allows you to escape static typing when necessary.

    Hope this helps...
    Bart

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.