给定传入的IEnumerable
,是否有任何内置方法可以为IEnumerable
中的所有项返回最佳匹配的基类型,它处理可空/不可空类型和继承?
这样的事情:
var hs = new HashSet<object> {1,2,3,null};
Type t = GetSharedType(hs); //returns typeof(int?)
hs = new HashSet<object> {new BaseClass(), new DerivedClass()};
t = GetSharedType(hs); //returns typeof(BaseClass)
hs = new HashSet<object> {"1", 1};
t = GetSharedType(hs); //returns typeof(object) or null
(我知道我可以写自己的;我的问题是,如果有内置的东西)。
答案 0 :(得分:2)
不,没有内置机制来执行此操作。您可以合并多个reflection APIs。
首先,您可以使用GetType()检索集合中每个对象的实际类型:
IEnumerable<Type> realTypes = hs.Select(o => o.GetType());
现在,您将收集具有Type属性和BaseType方法的GetInterfaces()类。 Ypu可以使用this code来获取每种类型的所有层次结构:
public static IEnumerable<Type> GetParentTypes(this Type type)
{
// is there any base type?
if ((type == null) || (type.BaseType == null))
{
yield break;
}
// return all implemented or inherited interfaces
foreach (var i in type.GetInterfaces())
{
yield return i;
}
// return all inherited types
var currentBaseType = type.BaseType;
while (currentBaseType != null)
{
yield return currentBaseType;
currentBaseType= currentBaseType.BaseType;
}
}
您可以使用它来获取层次结构的集合:
IEnumerable<IEnumerable<Type>> baseTypes = realTypes.Select(t => t.GetParentTypes());
下一步是将所有此列表合并为仅具有相交的值。您可以使用Enumerable.Intersect方法和this代码执行此操作:
public static IEnumerable<T> IntersectAllIfEmpty<T>(params IEnumerable<T>[] lists)
{
IEnumerable<T> results = null;
lists = lists.Where(l => l.Any()).ToArray();
if (lists.Length > 0)
{
results = lists[0];
for (int i = 1; i < lists.Length; i++)
results = results.Intersect(lists[i]);
}
else
{
results = new T[0];
}
return results;
}
最后,我们有:
IEnumerable<Type> realTypes = hs.Select(o => o.GetType());
IEnumerable<IEnumerable<Type>> baseTypes = realTypes.Select(t => t.GetParentTypes());
IEnumerable<Type> inersectedBaseTypes = IntersectAllIfEmpty(baseTypes);
然后我们可以使用Type.IsAssignableFrom()方法迭代每个类型并确保其中一个类型只能从它们自己分配:
Type mostConcreteType = inersectedBaseTypes.Where(t => inersectedBaseTypes.Count(bt => t.IsAssignableFrom(bt)) == 1).FirstOrDefault();
答案 1 :(得分:-1)
否,没有内置类型可以执行此操作。正如你自己确定的那样,你必须自己写作。像
这样的东西public static Type GetEnumerableType<T>(this IEnumerable<T> enumerable)
{
return typeof(T);
}