Detect and Reflect a Generic List
We have a project that uses reflection quite a bit. If you use any kind of mapper chances are you too are using reflection. One gotcha with reflection is the name of the properties, unless you make some other infrastructure to support mapping one name to another chances are you won’t get the data you desire.
What is This About
This post is not about creating your own mapper, although it could help. This post is more about a specific problem. I recently had to try to reflect out data for a RestAPI. We did not want to reflect out the entire object, it would be too much data and too large of a response. Plus we want the RestAPI to be as fast as possible. To solve this we decided that part of the call would be to specify the desired fields or return some very basic default fields. This was fairly straight forward until it came to the Generic Lists (List<T>) or ICollection objects. We did not want to reflect out those objects in their entirety as well.
As usual I thought this might have been done before, so I set about searching. StackOverflow is your friend, but it is your friend that knows almost too much. You will find a lot of questions and a lot of answers and while most were partially right I quickly noticed a flaw.
One such answer was to simply look for things being IEnumerable. That will work, but guess what else is IEnumerable. You may have forgotten it, a String. Who wants to reflect out an IEnumerable of type Character?
I created two methods to check for IsGenericList and IsICollection. For the List I used return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>); , for the ICollection I used result = (type.Namespace == “System.Collections.Generic”);
This is where I again fell back to the ExpandoObject and IDictionary<string, object>. These allow you to easily create an object and add properties dynamically at run time.
An Example Project
I realize this is a lot of reading and not much code. So I created a console application to show all of this stuff. The link will take you to a GitHub repository.
The example is very simple, I just wanted something that covered all of this stuff and worked. I have three data objects in my Models folder; Person, Purchase, and Review. The Person object contains a List of both Purchase and Review objects. I created a single person object with the appropriate data to reflect out.
Since it is a console application it reflects out into one long string, but you will get the idea. Most of the work takes place in the DataMapper.cs. You will notice I check for the PropertyType to be null, this could very well happen if someone did not send the proper name over that matches something on your object.
You will also notice a comment in there about working with IDictionary. You cannot have duplicate keys, so you may have to get creative with those keys.
While none of my objects in this example were ICollection, it will basically work like List<T>. There are methods in there to handle it, you just have to do some extra work in the ReflectICollection method. Mainly you have to flesh out the switch statement.
I hope this helped you with reflecting a List<T> or ICollection. It was a fun challenge for me that really enjoyed. Thank you very much for taking the time to read my post.