Two existing approaches are to see if the object implements IEnumerable<T>
or to check the type of the first item in the set. The first relies on the object actually implementing IEnumerable<T>
, and the second only works if all of the items in the sequence are of the same derived type.
One interesting question you might ask is what types do all of the items have in common, or what is the most narrow type that is common among all of the items.
We'll start out with a simple helper method. Given a type it will return a sequence of that type and all of it's base types.
public static IEnumerable<Type> getBaseTypes(Type type)
{
yield return type;
Type baseType = type.BaseType;
while (baseType != null)
{
yield return baseType;
baseType = baseType.BaseType;
}
}
Next we'll have a method to get all of the common types for a sequence by first finding all of the most derived types, then getting all of the base types for each Type in the sequence, and finally using intersect
to get only those items they all have in common:
public static IEnumerable<Type> getCommonTypes(IEnumerable source)
{
HashSet<Type> types = new HashSet<Type>();
foreach (object item in source)
{
types.Add(item.GetType());
}
return types.Select(t => getBaseTypes(t))
.Aggregate((a, b) => a.Intersect(b));
}
Note that the ordering of the types in the first method is from most derived to least derived, and Intersect
maintains ordering, so the resulting sequence will be in order from most derived to least derived. If you want to find the most narrow type common to all of these types then you can simply use First
on the result of this method. (Note that since everything derives from object
there will always be at least one type returned here unless there are no items in the original IEnumerable
.