views:

35

answers:

2

I would like to get the Type of item that a BindingSource is hooked up to or configured for. The BindingSource.DataSource property can be set to an object, list, or type. If it is a Type, it obviously does not have a bound item yet, but I would still like to get the Type. For a List, I need the item Type, not the list type.

I currently have a custom list type for business objects that implement an IListItemType interface, that I created to solve this problem a while back. I would now like to get this working in a more generic fashion so that it will work with any list.

I've looked through the API docs for for a good way to do this, but so far I have not had any luck. Am I missing something or is this just something I can not or should not be doing?

+1  A: 

There is no completely generic way to get the "type" of the list. The most common method is to examine the first item, but this can be misleading as you can have objects that are of a more specific type in a collection that is less specific (in other words, the collection might be a List<object>, but the first item might be a string, leading you to guess that it's a List<string>). If you're confident that all of the elements will be the same type (meaning none are more specific than the generic type of the collection or than any of the other objects), then examining the first item is the easiest.

Apart from that, you could examine the list's actual type using GetType and check its interfaces. Chances are that any collection that's strongly typed is going to implement IEnumerable<T>, so you can iterate over its interfaces looking for IEnumerable that's generic, then look at its generic type arguments. It's (more than) a little hokey, but it should work.

TL;DR Version

Try this. Assuming you're using .NET 3.5 and have the list stored in a variable called list:

var listType = list.GetType().GetInterfaces()
              .Where(t => t.Name == "IEnumerable" && t.IsGenericType)
              .Select(t => t.GetGenericArguments()[0]).FirstOrDefault();

As long as the list implements IEnumerable<T>, this will give you T. If it doesn't, chances are the list type is object anyway.

Adam Robinson
After looking into this, the GetItemProperties method looks like it is not going to be much help. You have to pass in a list of properties and then it will return the ones that exist on the item. So this gets me back to the issue of how do I get the item type to get the list of properties. I will edit the question to remove the incorrect speculation on that point.
Preston
@Preston: Have a look at the edit.
Adam Robinson
There is enough to think about here that I am pretty sure there is not going to be way to get the item type directly from the BindingSource as I had hoped. I think I just need to limit my scope and assume that the BindingSource is going to have a generic list type or a type derived from a generic list type set as the DataSource and just move on from there... or a directly bound single item. Anyway you get the idea, de-scope the edge cases and the problem goes away. Thanks for you thoughts.
Preston
@Preston: Yeah, unfortunately there's no completely generic way to do it. I do think, though that if you assume that: 1) Any list (collection, not necessarily `List<T>`) that's strongly typed will implement `IEnumerable<T>` for the desired type T, and 2) Any non-strongly typed list will implement `IEnumerable` and have desired type of `object`, and 3) Anything else is a single-bound object, then you'll cover 99% of the possibilities.
Adam Robinson
A: 

I recently ran accross this in the framework.

System.Windows.Forms.ListBindingHelper.GetListItemType() and GetListItemProperties()

This class has everything I was looking for.

Preston