tags:

views:

40

answers:

3

LinQ contains the method Cast which casts each entry in the list to type T. Lets say we have a list which looks like the following:

List<Object> obj = new List<Object>();
obj.Add("A");
obj.Add("B");

A working cast could be

var list = obj.Cast<string>();

What I would like to work

Type t = typeof(String);
Object list = obj.Cast(t);

A solution would be to use reflection and genericly create a list and populate it but I was wondering if there exist any better solution? Heard that .NET 4.0 should support some co/contra-variance which may be a way to do it.


Extra Information and Reflection Soulution

The error I get is the following The model item passed into the dictionary is of type System.Collections.Generic.List1[IStatisticEntry], but this dictionary requires a model item of type System.Collections.Generic.List1[CrashStatistic+CrashEntry]. Note that CrashEntry implements IStaticEntry but cannot be casted because it is a generic type of the list.

I constructed the following solution through I would stille like something without Reflection:

    public static object Cast(this IEnumerable list, Type type)
    {
        var newList = Activator.CreateInstance(typeof(List<>).MakeGenericType(type));

        foreach (var item in list)
            newList.GetType().GetMethod("Add").Invoke(newList, new object[] { item });

        return newList;
    }
A: 

You do not need to cast something on the type that you will know only in runtime. The type of the object will not change because you will perform cast, if it was string it will be a string later and it do not matter if you will assign it to string or object variable.

You do not need to care about casting to a real object type while you are operating on reflection methods. It can stay as an object variable because while using reflection you can access all of it's real type members anyway without any cast.

ŁukaszW.pl
I added the error description above, think it gives a more clear idea of what I mean.
Søren L.
A: 

It's not possible to do this statically, any more than you can do it with a single object.

Type t = typeof(string);
var x = (t)obj; // invalid

However, it is possible to treat the elements dynamically so that a cast to the underlying type isn't necessary:

static void Main(string[] args)
{
    List<Object> obj = new List<Object>();
    obj.Add("A");
    obj.Add("B");

    var list = obj.Cast<dynamic>();
    foreach (var item in list)
    {
        Console.WriteLine(item[0]);
    }

    Console.ReadKey();
}
Stephen Cleary
Thanks for the response but I don't think that is a fix to the issue. I have a view which expects a model of a certain type and I got the type as a parameter. Added some information about the error in the problem description above
Søren L.
If you only have the run-time type (e.g., an instance of `Type`) and not the compile-time type (e.g., a `<T>` generic parameter), then you must use reflection or `dynamic` (and you'd have to change the view to use `dynamic`). So, your choices are: 1) Use reflection; 2) use `dynamic`, changing the view; 3) Pass the type as a generic parameter `<T>` instead of a `Type` instance.
Stephen Cleary
Fair enough, thanks for the clarity on the subject. With my amount of typoes I believe that the nicest way is the Reflection solution to ensure that the views still work with strongly typed models :)
Søren L.
A: 

I don't quite understand why you'd want to do this but you could invoke Enumerable.Cast<T> through reflection:

List<object> objectList = new List<object> { "Foo", "Bar" };
object stringSequence = typeof(Enumerable)
    .GetMethod("Cast", BindingFlags.Public | BindingFlags.Static)
    .MakeGenericMethod(typeof(string))
    .Invoke(null, new[] { objectList });

In which case the runtime type of stringSequence would implement IEnumerable<string>.

Trillian