How to create List<T> instance in C# file using Reflection
Asked Answered
A

3

10

HI, I have a requirement to create instance for list object at runtime using reflection. For example I have 2 classes like below,

class Class1
{
   List<Class2> class2List;
   public List<Class2> Class2List
   {
        get;set;
   }
}
class Class2
{
    public string mem1;
    public string mem2;
}

After creating the instance of Class1 at Runtime in another class Class3, I want to assign values to all the properties of the class. In this case, Class2List is a property of List<Class2>. At Runtime, I don't know the class type of List<Class2>. How can I initialize the property i.e. List<Class2> inside class3 at runtime.

Any suggestions are greatly appreciated...

Anglofrench answered 6/5, 2011 at 9:5 Comment(0)
P
20

Rather than question your motives or try to unpick what you're doing - I'm just going to answer the question in the title.

Given you have a type instance listElemType that represents the type argument that is to be passed to the List<> type at runtime:

var listInstance = (IList)typeof(List<>)
  .MakeGenericType(listElemType)
  .GetConstructor(Type.EmptyTypes)
  .Invoke(null);

And then you can work with the list through it's IList interface implementation.

Or, indeed, you can stop at the MakeGenericType call and use the type it generates in a call to Activator.CreateInstance - as in Daniel Hilgarth's answer.

Then, given a target object whose property you want to set:

object target; //the object whose property you want to set
target.GetType()
  .GetProperty("name_of_property")        //- Assuming property is public
  .SetValue(target, listInstance, null);  //- Assuming .CanWrite == true 
                                          //  on PropertyInfo

If you don't know the properties of the type represented by target, then you need to use

target.GetType().GetProperties();

to get all the public properties of that instance. However just being able to create a list instance isn't really going to be able to help you there - you'll have to have a more generic solution that can cope with any type. Unless you're going to be specifically targetting list types.

Sounds to me like you might need a common interface or base...

Prober answered 6/5, 2011 at 9:20 Comment(3)
Rather than creating zero-length arrays for the GetConstructor and Invoke calls, you can use Type.EmptyTypes for GetConstructor, and pass null to Invoke. Also, you'll have to cast the object returned by Invoke: var listInstance = (IList)(typeof(List<>) .MakeGenericType(listElemType) .GetConstructor(new Type[0]) .Invoke(new object[0]));Wendywendye
thanks - I knew about Type.EmptyTypes and the null to Invoke but I was just banging it out really quickly... The missing cast, however, was because I thought about adding the IList bit after I'd wrriten the code! Will update.Prober
just as what i'm looking forClamper
H
0

Why do you need to use reflection to set the property?
After you created the instance of Class1 you can simply set the property:

Class1 instance = Activator.CreateInstanc<Class1>();
instance.Class2List = new List<Class2>();
Highpowered answered 6/5, 2011 at 9:13 Comment(1)
Thanks for the response. However, I dont know what properties the class1 is having at Runtime. For example, I have given Class2, in real I dont know the class type. Then How can I do this.Anglofrench
B
0

Here a sample (without proper error handling!) that initializes the List property of Class1. What do you want to fill/initialize in a property/field of your object if you have an interface? What do you want to fill for other object types (maybe with more than 1 constructor parameter)?

Maybe an inversion of control container would serve you in your solution (like for example Ninject http://ninject.org/, Spring.Net http://www.springframework.net/, Unity http://unity.codeplex.com/) or the members are already correctly initialized in the objects you are using.

using System;
using System.Collections.Generic;

namespace ConsoleApplication3
{
    public sealed class Class1
    {
        //[1]better solution (this way you wouldn't require reflection at all)
        // private readonly List<Class2> _class2List = new List<Class2>();
        private List<Class2> _class2List;
        public List<Class2> Class2List 
        { 
            get { return _class2List; }
            set {
                    _class2List = value; //set not allowed if you apply [1] 
                }
        }
        public string TestPropertyToIgnore { get; set; }
    }

    public class Class2
    {
        public string Mem1;
        public string Mem2;
    }


    class Program
    {
        static void Main()
        {
            var typeClass1 = Type.GetType("ConsoleApplication3.Class1");
            var objectClass1 =  Activator.CreateInstance(typeClass1);

            foreach(var property in objectClass1.GetType().GetProperties())
            {
                var propertyType = property.PropertyType;
                if (!propertyType.IsClass 
                    || !property.CanRead 
                    || !property.CanWrite
                    || property.GetValue(objectClass1, null) != null
                    || !IsGenericListOfT(propertyType)
                    )
                {
                    continue;
                }

                property.SetValue(objectClass1, Activator.CreateInstance(propertyType), null);

            }

            //this would raise a NullReference exception if list is still null
            Console.WriteLine(((Class1) objectClass1).Class2List.Count);
        }

        private static bool IsGenericListOfT(Type propertyType)
        {
            return propertyType.IsGenericType
                   && propertyType.GetGenericTypeDefinition() == typeof (List<>);
        }
    }
}
Business answered 6/5, 2011 at 17:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.