有没有办法通过反射从IEnumerable中检索类型T?
例如,我有一个变量IEnumerable info; 我想通过反射来检索Child的类型。
例如,我有一个变量IEnumerable info; 我想通过反射来检索Child的类型。
IEnumerable<T> myEnumerable;
Type type = myEnumerable.GetType().GetGenericArguments()[0];
IEnumerable<string> strings = new List<string>();
Console.WriteLine(strings.GetType().GetGenericArguments()[0]);
打印 System.String
。
请查看 MSDN 上的 Type.GetGenericArguments
。
编辑:我相信这将解决评论中的问题:
// 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
接口,因此需要返回它们的枚举。
编辑:虽然我必须说,一个类实现多个 T
的 IEnumerable<T>
接口是一个糟糕的想法。
public static Type GetItemType<T>(this IEnumerable<T> enumerable)
{
return typeof(T);
}
我曾经遇到过类似的问题。所选答案适用于实际情况。
在我的情况下,我只有一个类型(来自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;
}
Type.GenericTypeArguments
- 仅适用于 dotNet Framework 版本 >= 4.5。
否则,请使用 Type.GetGenericArguments
。 - Кое Кто如果您了解 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);
Type type
参数而不是 object obj
参数的人来说,有一个小问题:你不能仅仅用 type
替换 obj.GetType()
,因为如果你传入 typeof(IEnumerable<T>)
,你将得到空值。为了解决这个问题,测试 type
本身是否是 IEnumerable<>
的泛型,然后再测试它的接口。 - Ian Mercer非常感谢讨论。我以此为基础编写了下面的解决方案,它可以很好地处理我所关心的所有情况(包括IEnumerable、派生类等)。我认为应该在这里分享一下,以防其他人也需要:
Type GetItemType(object someCollection)
{
var type = someCollection.GetType();
var ienum = type.GetInterface(typeof(IEnumerable<>).Name);
return ienum != null
? ienum.GetGenericArguments()[0]
: null;
}
someCollection.GetType().GetInterface(typeof(IEnumerable<>).Name)?.GetGenericArguments()?.FirstOrDefault()
- Mass Dot Net我知道这有点老旧,但我相信这种方法可以解决在评论中提到的所有问题和挑战。感谢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<>);
}
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<T>>>>>>>>
该方法应返回 T
。在简单情况下,可以使用另一种替代方法,即要么是 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;
}
只需使用 typeof(T)
编辑: 如果您没有 T,请在实例化对象上使用 .GetType().GetGenericParameter()。
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;
}
}