从IEnumerable <t> </t>获取类型T.

时间:2009-05-25 12:12:43

标签: c# generics reflection

有没有办法通过反射从T检索IEnumerable<T>类型?

e.g。

我有一个变量IEnumerable<Child>信息;我想通过反思检索Child的类型

13 个答案:

答案 0 :(得分:132)

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

正是如此,

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

打印System.String

Type.GetGenericArgumentsMSDN

编辑:我相信这会解决评论中的问题:

// 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]);
}

有些对象实现了多个通用IEnumerable,因此必须返回它们的枚举。

编辑尽管如此,我不得不说,一个班级为多个IEnumerable<T>实施T是一个糟糕的主意。

答案 1 :(得分:37)

我只是制作一个扩展方法。这适用于我投入的一切。

public static Type GetItemType<T>(this IEnumerable<T> enumerable)
{
    return typeof(T);
}

答案 2 :(得分:22)

我有类似的问题。所选答案适用于实际实例。 就我而言,我只有一个类型(来自PropertyInfo)。

当类型本身为typeof(IEnumerable<T>)而不是IEnumerable<T>的实现时,所选答案将失败。

对于这种情况,以下工作:

public static Type GetAnyElementType(Type type)
{
   // Type is Array
   // short-circuit if you expect lots of arrays 
   if (type.IsArray)
      return type.GetElementType();

   // type is IEnumerable<T>;
   if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof (IEnumerable<>))
      return type.GetGenericArguments()[0];

   // type implements/extends IEnumerable<T>;
   var enumType = type.GetInterfaces()
                           .Where(t => t.IsGenericType && 
                                  t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                           .Select(t => t.GenericTypeArguments[0]).FirstOrDefault();
   return enumType ?? type;
}

答案 3 :(得分:19)

如果你知道IEnumerable<T>(通过泛型),那么只有typeof(T)才有效。否则(对于object或非通用IEnumerable),检查已实现的接口:

        object obj = new string[] { "abc", "def" };
        Type type = null;
        foreach (Type iType in obj.GetType().GetInterfaces())
        {
            if (iType.IsGenericType && iType.GetGenericTypeDefinition()
                == typeof(IEnumerable<>))
            {
                type = iType.GetGenericArguments()[0];
                break;
            }
        }
        if (type != null) Console.WriteLine(type);

答案 4 :(得分:7)

非常感谢您的讨论。我用它作为下面解决方案的基础,适用于我感兴趣的所有情况(IEnumerable,派生类等)。以为我应该在这里分享以防任何人需要它:

  Type GetItemType(object someCollection)
  {
    var type = someCollection.GetType();
    var ienum = type.GetInterface(typeof(IEnumerable<>).Name);
    return ienum != null
      ? ienum.GetGenericArguments()[0]
      : null;
  }

答案 5 :(得分:2)

只需使用typeof(T)

即可

修改 或者如果没有T,则在实例化对象上使用.GetType()。GetGenericParameter()。

答案 6 :(得分:2)

对于更简单的情况,可选择IEnumerable<T>T - 请注意使用GenericTypeArguments代替GetGenericArguments()

Type inputType = o.GetType();
Type genericType;
if ((inputType.Name.StartsWith("IEnumerable"))
    && ((genericType = inputType.GenericTypeArguments.FirstOrDefault()) != null)) {

    return genericType;
} else {
    return inputType;
}

答案 7 :(得分:1)

这是对Eli Algranti解决方案的改进,因为它也适用于IEnumerable<>类型在继承树中任何级别的地方。

此解决方案将从任何Type获取元素类型。如果类型不是IEnumerable<>,它将返回传入的类型。对于对象,使用GetType。对于类型,请使用typeof,然后在结果上调用此扩展方法。

public static Type GetGenericElementType(this Type type)
{
    // Short-circuit for Array types
    if (typeof(Array).IsAssignableFrom(type))
    {
        return type.GetElementType();
    }

    while (true)
    {
        // Type is IEnumerable<T>
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IEnumerable<>))
        {
            return type.GetGenericArguments().First();
        }

        // Type implements/extends IEnumerable<T>
        Type elementType = (from subType in type.GetInterfaces()
            let retType = subType.GetGenericElementType()
            where retType != subType
            select retType).FirstOrDefault();

        if (elementType != null)
        {
            return elementType;
        }

        if (type.BaseType == null)
        {
            return type;
        }

        type = type.BaseType;
    }
}

答案 8 :(得分:1)

我知道这有点老了,但我相信这种方法将涵盖评论中所述的所有问题和挑战。感谢Eli Algranti激发了我的工作。

/// <summary>Finds the type of the element of a type. Returns null if this type does not enumerate.</summary>
/// <param name="type">The type to check.</param>
/// <returns>The element type, if found; otherwise, <see langword="null"/>.</returns>
public static Type FindElementType(this Type type)
{
   if (type.IsArray)
      return type.GetElementType();

   // type is IEnumerable<T>;
   if (ImplIEnumT(type))
      return type.GetGenericArguments().First();

   // type implements/extends IEnumerable<T>;
   var enumType = type.GetInterfaces().Where(ImplIEnumT).Select(t => t.GetGenericArguments().First()).FirstOrDefault();
   if (enumType != null)
      return enumType;

   // type is IEnumerable
   if (IsIEnum(type) || type.GetInterfaces().Any(IsIEnum))
      return typeof(object);

   return null;

   bool IsIEnum(Type t) => t == typeof(System.Collections.IEnumerable);
   bool ImplIEnumT(Type t) => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>);
}

答案 9 :(得分:0)

typeof(IEnumerable<Foo>)GetGenericArguments() [0]将返回第一个通用参数 - 在本例中为typeof(Foo)

答案 10 :(得分:0)

这是我通常的做法(通过扩展方法):

public static Type GetIEnumerableUnderlyingType<T>(this T iEnumerable)
    {
        return typeof(T).GetTypeInfo().GetGenericArguments()[(typeof(T)).GetTypeInfo().GetGenericArguments().Length - 1];
    }

答案 11 :(得分:0)

这是我不可读的Linq查询表达式版本..

public static Type GetEnumerableType(this Type t) {
    return !typeof(IEnumerable).IsAssignableFrom(t) ? null : (
    from it in (new[] { t }).Concat(t.GetInterfaces())
    where it.IsGenericType
    where typeof(IEnumerable<>)==it.GetGenericTypeDefinition()
    from x in it.GetGenericArguments() // x represents the unknown
    let b = it.IsConstructedGenericType // b stand for boolean
    select b ? x : x.BaseType).FirstOrDefault()??typeof(object);
}

请注意,该方法还考虑了非泛型IEnumerable,在这种情况下它返回object,因为它采用了Type而不是具体实例作为参数。顺便说一句,由于 x代表未知数,我发现this video令人迷惑,尽管这无关紧要..

答案 12 :(得分:0)

public static Type GetInnerGenericType(this Type type)
{
  // Attempt to get the inner generic type
  Type innerType = type.GetGenericArguments().FirstOrDefault();

  // Recursively call this function until no inner type is found
  return innerType is null ? type : innerType.GetInnerGenericType();
}

这是一个递归函数,它将首先深入泛型类型列表,直到获得没有内部泛型类型的具体类型定义。

我用以下类型测试了此方法: ICollection<IEnumerable<ICollection<ICollection<IEnumerable<IList<ICollection<IEnumerable<IActionResult>>>>>>>>

应返回IActionResult