3

From my question at here: Cast in List object

I accepted the answer using LINQ:

myA = myB.Cast<A>().ToList();

I have a question: we have any other solutions without using LINQ, because my application is using .NET Framework 2.0.

UPDATE: If I have several classes myB, myC, myD, myE, ... which derived from myA, I need a function which can convert a list to list (T maybe myB or myC or myD, ...) to avoid repeat same codes. The function input is a list<T> and the function output is a list<myA>.

Thanks.

Community
  • 1
  • 1
Leo Vo
  • 9,980
  • 9
  • 56
  • 78
  • You could write your own version which loops over, casts and collects into a typed collection. – Gishu Apr 19 '11 at 08:26

3 Answers3

5

A simple foreach will do the trick (for readability, i've named the classes Foo and Bar)

myFoos = new List<Foo>();
foreach (Bar bar in myBars)
{
  myFoos.Add((Foo)bar);
}

After question edit:

To convert a list of multiple child classes into a base class, I would create a class called BaseCollection, than would inherit from List, as usually some other operations are required of the lists as well. Some usefull methods might be:

 public class BaseCollection : List<Base>
 {
    public static BaseCollection ToBase<T>(IEnumerable<T> source) where T: Base
    {
       BaseCollection result = new BaseCollection();
       foreach (T item in source)
       {
          result.Add(item);
       }
       return result;
     }

    public static List<T> FromBase<T>(IEnumerable<Base> source) where T: Base
    {
       List<T> result = new List<T>();
       foreach (Base item in source)
       {
          result.Add((T)item);
       }
       return result;
     }


    public static List<T> ChangeType<T, U>(List<U> source) where T: Base where U:Base
    {        
        List<T> result = new List<T>();        
        foreach (U item in source)        
        {           
            //some error checking implied here
            result.Add((T)(Base) item);        
        }        
        return result;      
    }  

    ....
    // some default printing
    public void Print(){...}         
    ....
    // type aware printing
    public static void Print<T>(IEnumerable<T> source) where T:Base {....}
    ....
 }

That would enable me to easily cast any descendant to and from base class collections, and use them like this:

List<Child> children = new List<Child>();
children.Add(new Child { ID = 1, Name = "Tom" });
children.Add(new Child { ID = 2, Name = "Dick" });
children.Add(new Child { ID = 3, Name = "Harry" });

BaseCollection bases = BaseCollection.ToBase(children);
bases.Print();

List<Child> children2 = BaseCollection.FromBase<Child>(bases);
BaseCollection.Print(children2);
SWeko
  • 30,434
  • 10
  • 71
  • 106
  • +1: However you shouldn't need the `(Foo)bar` cast because `bar` has to be a `Foo`anyway. – Nick Apr 19 '11 at 08:29
  • No. This solution is bad. If I have several classes myB, myC, myD, myE, ... which derived from myA, I need a function which can convert a list to list (T maybe myB or myC or myD, ...) to avoid repeat same codes. Thanks. – Leo Vo Apr 19 '11 at 08:31
  • Just create a generic function then! – Nick Apr 19 '11 at 08:32
  • @Nick, it might, but this way it works both for Dog -> Animal, and Animal -> Dog (provided the animals are indeed dogs) – SWeko Apr 19 '11 at 08:32
  • @Lu Lu: this is just a code snippet, if you really have several classes, and use lists of them often, I would hardtype them into a FooCollection, BarCollection, BazCollection class which would be directly castable, and avoid repeating this kind of code all over the place (will edit the answer). – SWeko Apr 19 '11 at 08:35
  • @SWeko: I understand your solution, but we can't write a function like LINQ's Cast function? It is simple and we don't need to write FooCollection, BarCollection, BazCollection, ... – Leo Vo Apr 19 '11 at 08:38
  • @Lu Lu: The BaseCollection class in not necessary, it's just nice to have, since I can put methods like Print, CalculateCompexAverage, FeedAnimals..., whatever logic I need in there, so the list knows how to behave itself. – SWeko Apr 19 '11 at 08:47
  • @SWeko: Not working. I get a error: cannot convert from System.Collections.Generic.List.Enumerator' to 'System.Collections.Generic.IEnumerable when I call function ToBase. Can you give me an example. Thanks. – Leo Vo Apr 19 '11 at 08:54
  • @Lu Lu: Tried it, and it looks like it works, will include an example. – SWeko Apr 19 '11 at 09:05
2

For .NET 2.0 you could write your own Cast method, using the Linq code as a guideline:

public static class EnumerableHelper
{
    public static IEnumerable<TResult> Cast<TResult>(IEnumerable source)
    {
        IEnumerable<TResult> enumerable = source as IEnumerable<TResult>;
        if (enumerable != null) return enumerable;
        if (source == null) throw new ArgumentNullException("source");        
        foreach(object element in source)
        {
            yield return (TResult) element;
        }
    }
}

then use it as follows:

myA = new List<A>(EnumerableHelper.Cast<A>(myB));   
Joe
  • 122,218
  • 32
  • 205
  • 338
  • 1
    +1, using the source of the referent LINQ implementation to implement parts of it is always a good idea. – SWeko Apr 19 '11 at 09:12
1
    public static List<B> Cast<A,B>(List<A> aLIst) where A : B
    {
        List<B> ret = new List<B>( );

        foreach (A a in aLIst)
        {
            ret.Add(a);
        }

        return ret;
    }    
Nick
  • 25,026
  • 7
  • 51
  • 83