How to detect if T is IEnumerable<T2>, and if so get type of T2?
I'm aware of this question, and it's开发者_JAVA技巧 follow-up, and also this one, but I can't put them together in a way which will help me do what I want to do:
I have a generic type, and I want to check that T is a struct
OR if it implements IEnumerable<T2>
, then I'd like to check that T2 is a struct
.
So far, I've got to here ('scuse the scrappy code, this is experimental):
private class TestClass<T>
{
public TestClass()
{
Type type = typeof(T);
//(detecting T == IEnumerable<something> ommitted for clarity)
Type enumerableType = type.GetInterfaces()
.Where(t => t.IsGenericType)
.Select(t => t.GetGenericTypeDefinition())
.Where(t => t == typeof(IEnumerable<>))
.FirstOrDefault();
if(enumerableType != null)
{
Type enumeratedType = type.GetGenericArguments().First();
if(!enumeratedType.IsValueType) //throw etc...
}
}
}
The problem I have is that enumerableType
is IEnumerable<>
, so the enumeratedType
comes out as T
, not whatever I've passed in (eg. new TestClass<int[]>()
).
Your problem is that you've selected away the type that has all the data in favor of it's erased generic type template.
Try:
Type enumerableType = type.GetInterfaces()
.Where(t => t.IsGenericType)
.Where(t => t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.Select(t => t.GetGenericArguments()[0])
.FirstOrDefault();
From Matt Warren's Blog:
internal static class TypeSystem {
internal static Type GetElementType(Type seqType) {
Type ienum = FindIEnumerable(seqType);
if (ienum == null) return seqType;
return ienum.GetGenericArguments()[0];
}
private static Type FindIEnumerable(Type seqType) {
if (seqType == null || seqType == typeof(string))
return null;
if (seqType.IsArray)
return typeof(IEnumerable<>).MakeGenericType(seqType.GetElementType());
if (seqType.IsGenericType) {
foreach (Type arg in seqType.GetGenericArguments()) {
Type ienum = typeof(IEnumerable<>).MakeGenericType(arg);
if (ienum.IsAssignableFrom(seqType)) {
return ienum;
}
}
}
Type[] ifaces = seqType.GetInterfaces();
if (ifaces != null && ifaces.Length > 0) {
foreach (Type iface in ifaces) {
Type ienum = FindIEnumerable(iface);
if (ienum != null) return ienum;
}
}
if (seqType.BaseType != null && seqType.BaseType != typeof(object)) {
return FindIEnumerable(seqType.BaseType);
}
return null;
}
}
I believe this code does what you want it to.
You might want to clean it up a bit though.
public class TestClass<T>
{
public TestClass()
{
bool hasStruct = false;
Type t1 = this.GetType().GetGenericArguments()[0];
if(t1.IsValueType){
hasStruct = true;
}
if (t1.IsGenericType)
{
Type t = t1.GetGenericArguments()[0];
if (t.IsValueType)
{
hasStruct = true;
}
}
}
}
精彩评论