【问题标题】:How to get a base type of a IEnumerable [duplicate]如何获取 IEnumerable 的基本类型 [重复]
【发布时间】:2015-11-05 08:18:37
【问题描述】:

可能重复:
getting type T from IEnumerable<T>

我的属性类型为IEnumerable

public IEnumerable PossibleValues { get; set; }

我怎样才能发现它被实例化的基类型?

例如,如果它是这样创建的:

PossibleValues = new int?[] { 1, 2 }

我想知道类型是 'int'。

【问题讨论】:

  • @Arran,指的是通用版本
  • @Arran:不一定,如果OP显示Nullable&lt;int&gt;的数组,但想检索int的方面有任何意义。
  • 请注意,有些类型实现了IEnumerable,但没有实现IEnumerable&lt;T&gt;,或者它可以实现IEnumerable&lt;T&gt;,但序列中的所有项目实际上都是T的子类型,而不是实际的T 个实例。

标签: c# ienumerable


【解决方案1】:
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&lt;T&gt; 的情况。如果该类型多次实现IEnumerable&lt;T&gt;,它会任意选择一个实现。

【讨论】:

  • 谢谢,当我有足够的声誉时,我会回答你。
  • 我正在使用另一个答案,但学习效果很好。
  • @RaoniZacaron 我已经为你的问题投票了,所以你现在有足够的声誉来投票答案(恭喜)。不要忘记接受您正在使用的答案!
  • 已经完成了!谢谢你帮助我。
  • @phoog 至少在 .NET 4.5 中,如果我尝试在非通用类型上调用 GetGenericTypeDefinition(),我会收到 InvalidOperationException;编辑以在调用之前检查...
【解决方案2】:

如果你想要可能值的类型,你可以这样做:

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

【讨论】:

  • 在提取第一个序列之前,您需要检查序列是否具有值。
  • 这就是为什么我说“假设数组实际上有值”。
  • 如果它没有值,它可能只是不提供类型(仍然无法工作)但不会引发异常。
  • 谢谢,当我有足够的声誉时,我会回答你的。我正在使用您的第二个建议,正好符合我的需要。
  • @RaoniZacaron 同时,我认为无论声誉级别如何,您仍然可以接受答案(点击投票按钮下方的复选框)。
【解决方案3】:

现有的两种方法是查看对象是否实现IEnumerable&lt;T&gt; 或检查集合中第一项的类型。第一个依赖于实际实现IEnumerable&lt;T&gt; 的对象,而第二个仅在序列中的所有项都属于相同的派生类型时才有效。

您可能会问一个有趣的问题,即所有项目的共同点是什么类型,或者在所有项目中最常见的类型是什么。

我们将从一个简单的辅助方法开始。给定一个类型,它将返回该类型及其所有基类型的序列。

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 中没有项目。

【讨论】:

    猜你喜欢
    • 2018-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多