views:

229

answers:

1

I have several classes, that all derives from SuperClass.

When the classes are created, they all are put into a List(Of SuperClass). When I go through the list, i would like to downcast the SuperClass object to its baseObject, and put it into the correct list. (I have one list created for each of the sub types of SuperClass).

It is possible to determin:

 If TypeOf SuperClass Is SubClass Then
      listOfSubClass.Add(DirectCast(SuperCLass, SubClass)
 End If

but this is a lot of work, when there are several classes.

By using

SuperClass.GetType.FullName

I get the type of the subClass.

My question is: Is it possible to use this to dynamically cast the SuperClass object? in psudoCode:

For each SuperClass
     Dim temp As SuperClass.GetType.FullName = _
                       DirectCast(SuperCLass, SuperClass.GetType.FullName 
     list.add(temp)
Next

Edit: I was hoping I could use a variable instead of the creating one case for each SubClass and do it all in one loop.

+2  A: 

Have you considered using LINQ's OfType extension method? It wraps an enumerable and filters the elements so that only the ones of the specified type are returned. You could use it like this:

list.AddRange(superList.OfType(Of SubClass)())

or even:

list = superList.OfType(Of SubClass)().ToList()

Sorry if my syntax is off, it's been a while since I've used VB.NET


Edit: Example, as promised:

namespace Demo.ListFilter
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;

    class Program
    {
        private class SuperClass
        {
        }

        private class SubClassA :
            SuperClass
        {
        }

        private class SubClassB :
            SuperClass
        {
        }

        static void Main(string[] args)
        {
            var superList = new List<SuperClass>()
            {
                new SuperClass(),
                new SuperClass(),
                new SuperClass(),
                new SuperClass(),
                new SubClassA(),
                new SubClassA(),
                new SubClassA(),
                new SubClassB(),
                new SubClassB(),
                new SubClassB(),
                new SubClassB()
            };

            var listA = new List<SubClassA>();
            var listB = new List<SubClassB>();

            SplitList(superList, listA, listB);

            Console.WriteLine("List A: {0}", listA.Count);
            Console.WriteLine("List B: {0}", listB.Count);
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }

        static void SplitList(IList superList, params IList[] subLists)
        {
            foreach(var subList in subLists)
            {
                var type = subList.GetType().GetGenericArguments()[0];
                FilterList(superList, subList, type);
            }
        }

        static void FilterList(IList superList, IList subList, Type type)
        {
            var ofTypeMethod = typeof(Enumerable).GetMethod("OfType");
            var genericMethod = ofTypeMethod.MakeGenericMethod(type);
            var enumerable = (IEnumerable)genericMethod.Invoke(null, new[] { superList });

            foreach(var item in enumerable)
            {
                subList.Add(item);
            }
        }
    }
}

Another Edit: You could also combine the methods like this:

    static void SplitList(IList superList, params IList[] subLists)
    {
        var ofTypeMethod = typeof(Enumerable).GetMethod("OfType");

        foreach(var subList in subLists)
        {
            var subListType = subList.GetType();
            var type = subListType.GetGenericArguments()[0];
            var genericOfTypeMethod = ofTypeMethod.MakeGenericMethod(type);
            var enumerable = genericOfTypeMethod.Invoke(null, new[] { superList });

            var addRangeMethod = subListType.GetMethod("AddRange");
            addRangeMethod.Invoke(subList, new[] { enumerable });
        }
    }

Don't forget to add error handling!

Rory
The problem with this is that I have to do this for each SubClass, which will be a lot of work. I was hoping I could use a variable instead of the 'SubClass' and do it all in one loop.
eflles
You could create a method that takes the `System.Type` as an argument and uses reflection to build up a call to `OfType`. I could show you an example in C# if you wanted, but I'm afraid I'd just butcher it if I tried it in VB.
Rory
That would be great!
eflles
That was easier than I thought, hope it helps.
Rory