Monday, November 15, 2010

Create a List Dynamically With Reflection

I wanted to do more with the Dynamic List that I put up a little while ago. I wanted a method that I could pass any type, and get a List of that type out of it. After a bit of playing around, I was able to get what I wanted using System.Reflection. Here is the code:
1:  private object GetList(object[] sourceArray, Type arrayType) {
2:        Type listType = typeof(List<>).MakeGenericType(new System.Type[] { arrayType });
3:        var list = Activator.CreateInstance(listType);
4:        MethodInfo mi = listType.GetMethod("Add");
5:        foreach (object item in sourceArray) {
6:          mi.Invoke(list, new object[] { item });
7:        }
8:        return list;
9:      }  

What I did was to first create an instance of the List. Then set the nested type to be the type of the calling type. This is all done using the Type class' MakeGenericType Method. All this does is create a List were T is the type that is passed as the parameter. I still need to instantiate this monstrosity. I do that in the next line of code, using the System.Activator class' CreateInstance method. After that I have an actual list. Now I need to populate it.
Because we don't know what types and classes we are dealing with at Design Time, we can't just call Class.Method() to make things work. I first need to find the specific method I need. To do that I call System.Reflection.Type's GetMethod method. This comes out as a System.Reflection.MethodInfo type, thus the creation of the MethodInfo variable.
From here I simply iterate through the objects in the array passed in to the method, and Add them to the List object.

There is one small issue... The return is not exactly what you would expect. It is not a List of the type you pass it, rather it is a single object, of type object. The good news is that this object can be casted as the proper List when you get back to your calling method.

For instance, here is my calling method:
1:  protected void butPeople_Click(object sender, EventArgs e) {
2:        Type peopleType = typeof(People);
3:        List<People> people = new List<People>();
4:        people = GetList(GetPeople(), peopleType) as List<People>;
5:        GridView1.DataSource = people;
6:        GridView1.DataBind();
7:        GridView1.Visible = true;
8:      }  

You can see in line 4 where I call the GetList method. I send it a custom type of People, along with an array of People. As I mentioned above, the return type of the GetList method is object, but this can be casted in to the type that we wanted it to be, as seen with the "as List" on line 4.

No comments:

Post a Comment