可能重复:
从 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>
了不止一次,它会任意选择一个实现。
如果您想要可能值的类型,您可以这样做:
var type = PossibleValues.GetType().ToString(); // "System.Nullable`1[System.Int32][]"
或者,如果您想要包含在 PossibleValues 中的项目的类型,您可以执行此操作(假设数组实际上具有您的问题中描述的值):
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();
}
现有的两种方法是查看对象是否实现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
.