bevacqua
bevacqua

Reputation: 48486

Type casting, a runtime alternative to Cast<T>?

I have an IList<object> where every single object is an instance of a type T (which I don't know at compile-time).

I need an IList<T> out of this. I can't use Cast since I don't know the type at compile time, and there isn't a Cast(Type) overload I could use.

This is what I currently have in place:

private object Map(IList<ApiCallContext> bulk)
{
    // god-awful way to build a IEnumerable<modelType> list out of Enumerable<object> where object is modelType.
    // quoting lead: "think whatever you do it will be ugly"
    Type modelType = model.Method.ModelType;

    if (bulk.Count > 0)
    {
        modelType = bulk.First().Parameters.GetType();
    }
    Type listType = typeof(List<>).MakeGenericType(modelType);
    object list = Activator.CreateInstance(listType);
    foreach (object value in bulk.Select(r => r.Parameters))
    {
        ((IList)list).Add(value);
    }
    return list;
}

What I'm thinking about is maybe I could create a new LooseList class that implements IList and just works around the casting, seems better than what I currently have but it still sounds way too clunky.

Upvotes: 2

Views: 1190

Answers (1)

Jon Skeet
Jon Skeet

Reputation: 1500665

If you really need to do exactly as you've stated, I'd first separate this out into "context-specific code" and "reusable code". Effectively you want something like this:

public static IList ToStrongList(this IEnumerable source, Type targetType)

I would implement that by writin a strongly-typed method, and then calling it via reflection:

private static readonly MethodInfo ToStrongListMethod = typeof(...)
    .GetMethod("ToStrongListImpl", BindingFlags.Static | BindingFlags.NonPublic);

public static IList ToStrongList(this IEnumerable source, Type targetType)
{
    var method = ToStrongListMethod.MakeGenericMethod(targetType);
    return (IList) method.Invoke(null, new object[] { source });
}

private static List<T> ToStrongListImpl<T>(this IEnumerable source)
{
    return source.Cast<T>().ToList();
}

Upvotes: 4

Related Questions