Rustam Ganeyev
Rustam Ganeyev

Reputation: 944

Convert List<object> to List<Type>, Type is known at runtime

I am implementing some kind of deserialization and struggled with a next problem:

I have List<object> and System.Reflection.Field, it's FieldType can be List<string>, List<int> or List<bool>, so I need to convert from List<object> to that types.

public static object ConvertList(List<object> value, Type type)
{
   //type may be List<int>, List<bool>, List<string>
}

I can write each case separately, but there should be a better way using reflection.

Upvotes: 27

Views: 41607

Answers (8)

DLeh
DLeh

Reputation: 24405

Not sure if this helps at all, but can you use Linq Cast?

List<object> theList = new List<object>(){ 1, 2, 3};
List<int> listAsInt = theList.Cast<int>().ToList();

Upvotes: 17

N-ate
N-ate

Reputation: 6943

Here is an extension method similar to the linq extension method except it takes an argument that is a type instead of a type parameter:

public static IList CastToList(this IEnumerable source, Type itemType)
{
    var listType = typeof(List<>).MakeGenericType(itemType);
    var list = (IList)Activator.CreateInstance(listType);
    foreach (var item in source) list.Add(item);
    return list;
}

Usage:

var list = new List<object>();
list.add(1);
list.add(2);
var boxedIntList = list.CastToList(typeof(int)); //type is object{List<int>}

Upvotes: 0

Richiban
Richiban

Reputation: 5940

I believe what you want is:

public static object ConvertList(List<object> value, Type type)
{
    var containedType = type.GenericTypeArguments.First();
    return value.Select(item => Convert.ChangeType(item, containedType)).ToList();
}

Example usage:

var objects = new List<Object> { 1, 2, 3, 4 };

ConvertList(objects, typeof(List<int>)).Dump();

I'm not sure how useful this is though... It highlights the insanely useful Convert.ChangeType method I guess!


Update: Since others have correctly pointed out that this doesn't actually return a List<T> (where T is the type in question) and therefore might not fully answer the question at hand, I have chosen to provide a more up to date answer:

public static object ConvertList(List<object> items, Type type, bool performConversion = false)
{
    var containedType = type.GenericTypeArguments.First();
    var enumerableType = typeof(System.Linq.Enumerable);
    var castMethod = enumerableType.GetMethod(nameof(System.Linq.Enumerable.Cast)).MakeGenericMethod(containedType);
    var toListMethod = enumerableType.GetMethod(nameof(System.Linq.Enumerable.ToList)).MakeGenericMethod(containedType);

    IEnumerable<object> itemsToCast;

    if(performConversion)
    {
        itemsToCast = items.Select(item => Convert.ChangeType(item, containedType));
    }
    else 
    {
        itemsToCast = items;
    }

    var castedItems = castMethod.Invoke(null, new[] { itemsToCast });

    return toListMethod.Invoke(null, new[] { castedItems });
}

If you don't need the conversion (so the type of each value is actually correct, and you don't have ints in strings etc), then remove the performConversion flag and the associated block.


Example: https://dotnetfiddle.net/nSFq22

Upvotes: 23

Vladimir Roytman
Vladimir Roytman

Reputation: 41

    /// <summary>
    /// Converts list of items into typed list of item of new type
    /// </summary>
    /// <example><code>
    /// Consider source to be List<object>, newItemType is typeof(string), so resulting list wil have type List<string>
    /// </code></example>
    /// <param name="newItemType">New item type</param>
    /// <param name="source">List of objects</param>
    /// <returns>Typed List object</returns>
    public static IList ConvertList(Type newItemType, IList source)
    {
        var listType = typeof(List<>);
        Type[] typeArgs = { newItemType };
        var genericListType = listType.MakeGenericType(typeArgs);
        var typedList = (IList)Activator.CreateInstance(genericListType);
        foreach (var item in source)
        {
            typedList.Add(item);
        }
        return typedList;
    }

Upvotes: 4

Guillaume
Guillaume

Reputation: 13138

The type is only known at runtime so I guess generic method isn't the way to go

public static object ConvertList(List<object> value, Type type)
{
   IList list = (IList)Activator.CreateInstance(type);
   foreach (var item in value)
   {
      list.Add(item);
   }
   return list;
}

Upvotes: 12

Maximc
Maximc

Reputation: 1762

 public static object ConvertList<T>(List<object> value) where T : class
    {
        var newlist = value.Cast<T>().ToList();
        return newlist;
    }

or

  public static List<T> ConvertList<T>(List<object> value) where T : class
    {
        List<T> newlist = value.Cast<T>().ToList();
        return newlist;
    }

Upvotes: 2

kevin
kevin

Reputation: 2213

public static List<T> ConvertType<T>(List<object> list) {
    var list2 = new List<T>();
    for(int i=0;i<list.Count;i++) list2.Add((T)list[i]);
    return list2;
}

Upvotes: 0

Only a Curious Mind
Only a Curious Mind

Reputation: 2857

Try this:

public static List<T> ConvertList<T>(List<object> list)
{
    List<T> castedList = list.Select(x => (T)x);
    return castedList;
}

Call:

List<object> myList = new List<object> {"test", "foo", "bar"};
List<string> stringList = ConvertList<string>(myList);

Upvotes: 1

Related Questions