Getting Type T from Ienumerable<T>

getting type T from IEnumerable T


IEnumerable<T> myEnumerable;
Type type = myEnumerable.GetType().GetGenericArguments()[0];

Thusly,

IEnumerable<string> strings = new List<string>();
Console.WriteLine(strings.GetType().GetGenericArguments()[0]);

prints System.String.

See MSDN for Type.GetGenericArguments.

Edit: I believe this will address the concerns in the comments:

// returns an enumeration of T where o : IEnumerable<T>
public IEnumerable<Type> GetGenericIEnumerables(object o) {
return o.GetType()
.GetInterfaces()
.Where(t => t.IsGenericType
&& t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.Select(t => t.GetGenericArguments()[0]);
}

Some objects implement more than one generic IEnumerable so it is necessary to return an enumeration of them.

Edit: Although, I have to say, it's a terrible idea for a class to implement IEnumerable<T> for more than one T.

Get type of T in IEnumerable T


If T is List<T>

// add error checking to taste
var typeOfEnumerable = typeof(T).GetInterfaces().Where(i => i.IsGenericType)
.Single(i => i.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.GetGenericArguments().First();

See it in action.

If T is IEnumerable<T>

// add error checking to taste
var typeOfEnumerable = typeof(T).GetGenericArguments().First();

Important notes

You really should think about what MyClass is trying to do here. Why does it want to special-case for T being an IEnumerable<X>? Perhaps some constraints should be added on T? It's not possible to answer these and other important questions without more concrete information, but you really should do so.

Also, did you name the method GetType by accident or on purpose? It's really, really, really not a good idea to hide object.GetType like that, so I would suggest you rename that method.

How to get a base type of a IEnumerable

You can do this if you want the type of PossibleValues:

var type = PossibleValues.GetType().ToString(); // "System.Nullable`1[System.Int32][]"

Or you can do this if you want the type of an item contained in PossibleValues (assuming the array actually has values as described in your question):

var type = PossibleValues.Cast<object>().First().GetType().ToString(); // "System.Int32"



EDIT

If it's a possibility that the array may contain no items, then you'll have to do some null checking, of course:

var firstItem = PossibleValues.Cast<object>().FirstOrDefault(o => o != null);
var type = string.Empty;
if (firstItem != null)
{
type = firstItem.GetType().ToString();
}

Checking if Type or instance implements IEnumerable regardless of Type T

The following line

return (type is IEnumerable);

is asking "if an instance of Type, type is IEnumerable", which clearly it is not.

You want to do is:

return typeof(IEnumerable).IsAssignableFrom(type);

How to check whether a Generic Type T is IEnumerable T' where T' is unkown

Because you are only calling .ToString() you actually don't really care what T is, only if it implements IEnumerable or not. Here is how to do it without reflection and just using IEnumerable instead of IEnumerable<T>, I do my own logic for String.Join because it made it easier to code the recursive logic.

internal static class ExtensionMethods
{
public static String Join<T>(this IEnumerable<T> enumerable)
{
StringBuilder sb = new StringBuilder();
JoinInternal(enumerable, sb, true);
return sb.ToString();
}

private static bool JoinInternal(IEnumerable enumerable, StringBuilder sb, bool first)
{
foreach (var item in enumerable)
{
var castItem = item as IEnumerable;
if (castItem != null)
{
first = JoinInternal(castItem, sb, first);
}
else
{
if (!first)
{
sb.Append(",");
}
else
{
first = false;
}

sb.Append(item);
}
}
return first;
}
}

Here is a test program I wrote that shows it all works (it tests classes, structs, and IEnumerables 3 layers deep).

EDIT: Per your comment here is another version that flattens out the nested IEnumerables, you can do whatever you want to each element when you are done.

internal static class ExtensionMethods
{
public static IEnumerable<T> SelectManyRecusive<T>(this IEnumerable enumerable)
{
foreach (var item in enumerable)
{
var castEnumerable = item as IEnumerable;
if (castEnumerable != null
&& ((typeof(T) != typeof(string)) || !(castEnumerable is string))) //Don't split string to char if string is our target
{
foreach (var inner in SelectManyRecusive<T>(castEnumerable))
{
yield return inner;
}
}
else
{
if (item is T)
{
yield return (T)item;
}
}
}
}
}

There also was a bug I ran in to that I think may afffect my first part of my answer, a string is technically a IEnumerable<char> so a IEnumerable<string> could be also seen as a IEnumerable<IEnumerable<char>> and it may put too many , in. This second version has a check for that.

Test program showing how to use this method and String.Join together.

Why can't I replace IEnumerable T by a generic type variable in extension method?


Why?

For exactly the reason stated in the error message: you're trying to use IEnumerable<Customers> as the type argument for E, but E has this constraint:

where E : System.Linq.IQueryable<T>

And how can it be fixed?

It can't, assuming I understand what you're trying to achieve.

There's a fundamental problem with the "simplification" you're trying to achieve: you don't actually have full duplication in your original MySelect1 methods. The first calls AsEnumerable() and the second calls AsQueryable(). You're trying to replace those with a cast, and that's just not going to work.

There's a further problem, even with your original methods: you're accepting Func<T, V> f as a parameter for your queryable-based method, which means any time you call Select or similar and passing in f, you'll be calling Enumerable.Select instead of Queryable.Select. To really use IQueryable<> properly, you should accept Expression<Func<T, V>> f instead. At that point, you won't need to call AsQueryable anyway.

Your two methods "should" take radically different paths based on whether you're using LINQ to Objects or a different LINQ provider (e.g. LINQ to SQL), and that can't be hidden as a pure implementation detail without significant changes that would probably make it less useful than you want anyway.

Create a Generic IEnumerable T given a IEnumerable and the member datatypes

You can use reflection to call Cast<> with a runtime type. See this answer: How to call a generic method through reflection

However, at some point you'll still have to know the type of the item at compile time if you ever want to manipulate it as such without reflection. Just having an IEnumerable<T> instance cast as an object/IEnumerable still won't really do you any more good than just having the IEnumerable by itself. It's likely that you need to rethink what you're doing.



Related Topics



Leave a reply



Submit