views:

84

answers:

3

I have a function that uses reflection to set properties of object A from object B. At one point, I need to instantiate a generic collection. However, I am unable to get it working. Here is what I have now:

IList list = destProperty.PropertyType.GetGenericTypeDefinition()
                .MakeGenericType(destProperty.PropertyType.GetGenericArguments())
                .GetConstructor(Type.EmptyTypes)
                .Invoke(null) as IList;

I am trying to set the value of the destProperty. It has to be a List At runtime, the destProperty is of type ICollection<>. I think what's happening is that since ICollection is an interface, it has no constructor. What is the proper way to instantiate it then?

Thanks!

A: 

You can't instantiate an interface. What you can do is instantiate a generic type that implements that interface. In your case, you'll want to get the Type representing the generic List<>, then call MakeGenericType on it.

That assumes that you know List will always work. If not, I suppose you could search for types that implement the interface, but how you'd pick one and be sure it has a parameterless constructor seems complicated to me. Seems like it would be easier to get the actual type of the object rather than the interface in that case.

Philip Rieck
A: 

One technique is to declare a static method taking the same generic arguments as the list you want to create. Then you can pull the arguments from the property to invoke the method.

Type interfaceType = destProperty.PropertyType;
return typeof(MyClass)
    .GetMethod("CreateList", BindingFlags.NonPublic | BindingFlags.Static)
    .MakeGenericMethod(interfaceType.GetGenericArguments())
    .Invoke(null, new object[] { });

private static IList CreateList<T>()
{
    return new List<T>();
}
Michael L Perry
+1  A: 

I've re-written your code, into the form of an example (hopefully that matches what you're trying to do! =), to try and make it clearer what the problem is:

public class Program
{
    public struct MyType
    {
        public ICollection<string> MyProperty { get; set; }
    }
    static void Main(string[] args)
    {
        var type = typeof(MyType);
        var properties = type.GetProperties();
        var destProperty = properties[0];

        var genericTypeDefinition = destProperty.PropertyType.GetGenericTypeDefinition();
        var madeGenericType = genericTypeDefinition.MakeGenericType(destProperty.PropertyType.GetGenericArguments());
        var ctor = madeGenericType.GetConstructor(Type.EmptyTypes);
    }
}

If you put a breakpoint on the penultimate brace you'll see that ctor comes back as null, which is because, as you correctly surmised, ICollection<T> doesn't have any constructors due to it being an interface.

Because of this, there's no "super-generic" way of doing this because there's no inherent way to say "what's the best implementation of ICollection<T> to use in this situation". You'll need to make that decision and new one, based on the information you get back from reflection.

Rob