views:

54

answers:

4

Let's say I have retrieved a System.Type object using reflection and want to use that type to convert a List<Object> into another List of that type.

If I try:

Type type = GetTypeUsingReflection();
var myNewList = listObject.ConvertAll(x => Convert.ChangeType(x, type)); 

I get an exception since the object does not implement the IConvertible interface. Is there a way around this or another way to approach this problem?

+4  A: 

Your proposed solution wouldn't actually work anyway - it'll just create another List<Object>, because the return type of ChangeType is Object.

Assuming you just want casting, you could do something like this:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

class Test
{
    private static List<T> ConvertListImpl<T>(List<object> list)
    {
        return list.ConvertAll(x => (T) x);
    }

    // Replace "Test" with the name of the type containing this method
    private static MethodInfo methodDefinition = typeof(Test).GetMethod
        ("ConvertListImpl", BindingFlags.Static | BindingFlags.NonPublic);

    public static IEnumerable ConvertList(List<object> list, Type type)
    {
        MethodInfo method = methodDefinition.MakeGenericMethod(type);
        return (IEnumerable) method.Invoke(null, new object[] { list });
    }

    static void Main()
    {
        List<object> objects = new List<object> { "Hello", "there" };
        List<string> strings = (List<string>) ConvertList(objects,
                                                          typeof(string));

        foreach (string x in strings)
        {
            Console.WriteLine(x);
        }
    }
}
Jon Skeet
A: 

Casting is of little use when the type is not known at design-time. Once you have your new list of objects cast to your new type, how are you going to make use of the new type? You can't call a method that the type exposes (without using more reflection)

KeithS
A: 

There's no way for the type system to go from a type variable storing type T to a generic parameter of type T.

Technically you can create a generic list of the correct type (using reflection), but the type information is not available at compile time.

Strilanc
A: 
Type type = typeof(int); // could as well be obtained by Reflection

var objList = new List<object> { 1, 2, 3 };
var intList = (IList) Activator.CreateInstance(
    typeof(List<>).MakeGenericType(type)
    );

foreach (var item in objList)
    intList.Add(item);

// System.Collections.Generic.List`1[[System.Int32, ...]]
Console.WriteLine(intList.GetType().FullName);

But why on Earth would you need it?

gaearon
Thanks, works like a charm! Well the reason is this: Let's say for the purpose of dependency injection that I via reflection can find classes which implements a certain interface with a method that takes a List<T> as argument. In runtime I don't know what T is but I can retrieve the type. Not the best of explanations but hopefully a hint.
Christian Zieger
You see, the reason I'm asking is because I recently worked on a layer that manipulated NHibenate objects and sync'ed different databases—and, as it was getting more complex, and we needed to keep things abstract, I started to introduce more and more reflection madness like this code sample. And then, at one point, I just removed generics and type safety (which was useless anyways because the values were obtained and set only through reflection), and making everything untyped and simple turned out to be the best solution which was hard to overestimate later. Keep things as simple as you can.
gaearon