可能是重复问题:
从IEnumerable<T>获取类型T
我有一个IEnumerable
类型的属性:
public IEnumerable PossibleValues { get; set; }
如何发现它实例化的基本类型?
例如,如果是像这样创建的:
PossibleValues = new int?[] { 1, 2 }
我想知道类型是“int”。
可能是重复问题:
从IEnumerable<T>获取类型T
我有一个IEnumerable
类型的属性:
public IEnumerable PossibleValues { get; set; }
如何发现它实例化的基本类型?
例如,如果是像这样创建的:
PossibleValues = new int?[] { 1, 2 }
我想知道类型是“int”。
Type GetBaseTypeOfEnumerable(IEnumerable enumerable)
{
if (enumerable == null)
{
//you'll have to decide what to do in this case
}
var genericEnumerableInterface = enumerable
.GetType()
.GetInterfaces()
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));
if (genericEnumerableInterface == null)
{
//If we're in this block, the type implements IEnumerable, but not IEnumerable<T>;
//you'll have to decide what to do here.
//Justin Harvey's (now deleted) answer suggested enumerating the
//enumerable and examining the type of its elements; this
//is a good idea, but keep in mind that you might have a
//mixed collection.
}
var elementType = genericEnumerableInterface.GetGenericArguments()[0];
return elementType.IsGenericType && elementType.GetGenericTypeDefinition() == typeof(Nullable<>)
? elementType.GetGenericArguments()[0]
: elementType;
}
这个例子有一些限制,可能会或可能不会涉及到您的应用程序。 它不能处理类型实现 IEnumerable
但不包含 IEnumerable<T>
的情况。如果该类型多次实现 IEnumerable<T>
,则它会随意选择一个实现。
GetGenericTypeDefinition()
方法,会抛出 InvalidOperationException 异常;因此已编辑代码,在调用该方法前进行检查... - Tobias Jtypeof(IEnumerable<>).IsAssignableFrom(type)
来检查 type
是否实现了泛型 IEnumerable 接口。 - Prophet Lambvar type = PossibleValues.GetType().ToString(); // "System.Nullable`1[System.Int32][]"
var type = PossibleValues.Cast<object>().First().GetType().ToString(); // "System.Int32"
编辑
如果数组可能不包含任何项目,则当然必须进行一些空值检查:
var firstItem = PossibleValues.Cast<object>().FirstOrDefault(o => o != null);
var type = string.Empty;
if (firstItem != null)
{
type = firstItem.GetType().ToString();
}
Cast<object>()
。 - bugged87Where(o => o != null)
来解决这个问题。 - Servy有两种现有方法可以查看对象是否实现了 IEnumerable<T>
,或者检查集合中第一个项目的类型。第一种方法依赖于对象实际上实现了 IEnumerable<T>
,而第二种方法仅在序列中的所有项目都是相同派生类型时才有效。
你可能会问一个有趣的问题,那就是所有项目共同具有哪些类型,或者说最窄的公共类型是什么。
我们将从一个简单的帮助方法开始。给定一个类型,它将返回该类型及其所有基类型的序列。
public static IEnumerable<Type> getBaseTypes(Type type)
{
yield return type;
Type baseType = type.BaseType;
while (baseType != null)
{
yield return baseType;
baseType = baseType.BaseType;
}
}
接下来我们将有一个方法来获取序列中所有常见类型,首先找到所有最派生的类型,然后获取序列中每个类型的基本类型,最后使用intersect
仅获取它们共有的项:
public static IEnumerable<Type> getCommonTypes(IEnumerable source)
{
HashSet<Type> types = new HashSet<Type>();
foreach (object item in source)
{
types.Add(item.GetType());
}
return types.Select(t => getBaseTypes(t))
.Aggregate((a, b) => a.Intersect(b));
}
Intersect
会保持排序,因此结果序列将按照从最派生到最不派生的顺序排列。如果你想找到所有这些类型共同拥有的最窄类型,那么可以简单地在这个方法的结果上使用First
。(请注意,由于所有东西都派生自object
,因此除非原始的IEnumerable
中没有项目,否则总会返回至少一个类型。)
Nullable<int>
数组的方面有任何重要意义,但想要检索int
。 - O. R. MapperIEnumerable
但没有实现IEnumerable<T>
,或者它可能实现了IEnumerable<T>
但是序列中的所有项实际上都是T的子类型而不是实际的T实例。 - Servy