jarlelin
jarlelin

Reputation: 55

Adding an instance of a type to a list of that type when instantiated by reflection

I'm trying populate the properties of several classes by using to reflection to assign default vaules to all their properties.

This is primarily done by using PropertyInfo.Setvalue(instance, value). I have a problem however when that property has a List of a specific class. I don't know that class type until run time.

To create that list and return to set by SetVaule() I am doing the following:

    private static IEnumerable<object> CreateAListContainingOneObject(Type type)
    {
        var listType = typeof(List<>).MakeGenericType(new Type[] { type });
        var generic = Activator.CreateInstance(listType);
        var dynamicList = generic as dynamic;

         var instance = new MySpecialType();
         var instance2 = Activator.CreateInstance(type);

        var typecheck = instance.GetType() == instance2.GetType();

        dynamicList.Add(instance);
        dynamicList.Add(instance2);
        return dynamicList;
    }

I have tried several options, but the one listed here is particularly interesting because when run the typecheck will be true, and the first Add will work, but the second will fail, telling me "The best overloaded Method 'Add(....)' has some invalid arguments".

PS. The list has to be a List of MyType or else I won't be able to set its value to the property by SetVaule(). Using a new List of object and adding my newly instantiated object of type myType will not work.

Edit: The reason I haven't used a generic method to call where I can instantiate a known type is because I'm doing this on a series of classes that inherit from my base class. They havea variety of properties and I can't know and dont want to write code fro each class and each property it can have. The call originates from something like this:

public static ABaseClass FillObjectWithDefaults(this ABaseClass myObject)
    {
        var properties = myObject.GetType().GetProperties();
        foreach (var p in properties)
        {
             var value = FindValue(p);
             p.SetValue(template, value);
        }
        return template;
    }

Upvotes: 2

Views: 512

Answers (2)

Rhumborl
Rhumborl

Reputation: 16609

You could use a second generic method to help you out, so you don't need to mess around with dynamics and Activation.

This just involves finding the helper method and invoking that to create and add the instance to the list. It also give you the option to invoke it generically.

private static IEnumerable<object> CreateAListContainingOneObject(Type type)
{
    var del = typeof(Program).GetMethod("CreateAGenericListContainingOneObject",
        BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(type);

    return del.Invoke(null, new object[] { }) as IEnumerable<object>;
}

private static List<T> CreateAGenericListContainingOneObject<T>()
    where T : new()
{
    return new List<T> { new T() };
}

Example DotNetFiddle

Upvotes: 1

DavidG
DavidG

Reputation: 118937

Activator.CreateInstance returns an object of type Object so the second Add can't work.

You can either cast it:

var instance2 = Activator.CreateInstance(type) as MySpecialType;
var instance2 = (MySpecialType)Activator.CreateInstance(type);

Or use dynamic instead of var:

dynamic instance2 = Activator.CreateInstance(type);

Personally, I'd probably change the function completely to use a generic type parameter like this:

private static IEnumerable<object> CreateAListContainingOneObject<T>()
{
    var listType = typeof(List<>).MakeGenericType(typeof(T));
    var generic = Activator.CreateInstance(listType);
    var dynamicList = generic as dynamic;

    var instance = new MySpecialType();

    var instance2 = (T)Activator.CreateInstance(typeof(T));

    var typecheck = instance.GetType() == instance2.GetType();

    dynamicList.Add(instance);
    dynamicList.Add(instance2);
    return dynamicList;
}

And call it like this:

var list = CreateAListContainingOneObject<MySpecialType>();

Upvotes: 0

Related Questions