C# 从 IEnumerable<T> 获取类型 T

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/906499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 02:31:30  来源:igfitidea点击:

getting type T from IEnumerable<T>

c#genericsreflection

提问by Usman Masood

is there a way to retrieve type Tfrom IEnumerable<T>through reflection?

有没有一种方法来检索类型TIEnumerable<T>通过反射?

e.g.

例如

i have a variable IEnumerable<Child>info; i want to retrieve Child's type through reflection

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

采纳答案by jason

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.

打印System.String

See MSDNfor Type.GetGenericArguments.

请参阅MSDN了解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 IEnumerableso it is necessary to return an enumeration of them.

一些对象实现了多个泛型,IEnumerable因此有必要返回它们的枚举。

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

编辑:虽然,我不得不说,对于一个类实现IEnumerable<T>多个T.

回答by Daniel Brückner

typeof(IEnumerable<Foo>).GetGenericArguments()[0]will return the first generic argument - in this case typeof(Foo).

typeof(IEnumerable<Foo>). 将返回第一个通用参数 - 在这种情况下。GetGenericArguments()[0]typeof(Foo)

回答by rein

Just use typeof(T)

只需使用 typeof(T)

EDIT:Or use .GetType().GetGenericParameter() on an instantiated object if you don't have T.

编辑:如果没有 T,则在实例化对象上使用 .GetType().GetGenericParameter()。

回答by Marc Gravell

If you know the IEnumerable<T>(via generics), then just typeof(T)should work. Otherwise (for object, or the non-generic IEnumerable), check the interfaces implemented:

如果你知道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);

回答by Bernardo

Thank you very much for the discussion. I used it as a basis for the solution below, which works well for all cases that are of interest to me (IEnumerable, derived classes, etc). Thought I should share here in case anyone needs it also:

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

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

回答by amsprich

I'd just make an extension method. This worked with everything I threw at it.

我只是做一个扩展方法。这对我投入的所有东西都有效。

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

回答by Rob Church

An alternative for simpler situations where it's either going to be an IEnumerable<T>or T- note use of GenericTypeArgumentsinstead of GetGenericArguments().

更简单的替代办法是要么将是一个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;
}

回答by Eli Algranti

I had a similar problem. The selected answer works for actual instances. In my case I had only a type (from a PropertyInfo).

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

The selected answer fails when the type itself is typeof(IEnumerable<T>)not an implementation of IEnumerable<T>.

当类型本身typeof(IEnumerable<T>)不是IEnumerable<T>.

For this case the following works:

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

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;
}

回答by Neo

This is an improvement on Eli Algranti's solution in that it will also work where the IEnumerable<>type is at any level in the inheritance tree.

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

This solution will obtain the element type from any Type. If the type is not an IEnumerable<>, it will return the type passed in. For objects, use GetType. For types, use typeof, then call this extension method on the result.

此解决方案将从 any 获取元素类型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;
    }
}

回答by H7O

this is how I usually do it (via extension method):

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

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