【问题标题】:Checking if Type or instance implements IEnumerable regardless of Type T检查 Type 或实例是否实现 IEnumerable 而不管 Type T
【发布时间】:2015-04-26 10:25:30
【问题描述】:

我正在对我当前的项目进行大量反思,并且我正在尝试提供一些帮助方法来保持一切整洁。

我想提供一对方法来确定一个类型或实例是否实现了IEnumerable——不管T是什么类型。这是我目前拥有的:

public static bool IsEnumerable(this Type type)
{
    return (type is IEnumerable);
}

public static bool IsEnumerable(this object obj)
{
    return (obj as IEnumerable != null);
}

当我使用测试它们时

Debug.WriteLine("Type IEnumerable:   " + typeof(IEnumerable).IsEnumerable());
Debug.WriteLine("Type IEnumerable<>: " + typeof(IEnumerable<string>).IsEnumerable());
Debug.WriteLine("Type List:          " + typeof(List<string>).IsEnumerable());
Debug.WriteLine("Type string:        " + typeof(string).IsEnumerable());
Debug.WriteLine("Type DateTime:      " + typeof(DateTime).IsEnumerable());
Debug.WriteLine("Instance List:      " + new List<string>().IsEnumerable());
Debug.WriteLine("Instance string:    " + "".IsEnumerable());
Debug.WriteLine("Instance DateTime:  " + new DateTime().IsEnumerable());

结果如下:

Type IEnumerable:   False
Type IEnumerable<>: False
Type List:          False
Type string:        False
Type DateTime:      False
Instance List:      True
Instance string:    True
Instance DateTime:  False

type 方法似乎根本不起作用——我预计至少直接匹配 System.Collections.IEnumerabletrue

我知道string 在技术上是可枚举的,尽管有一些注意事项。但是,在这种情况下,理想情况下,我需要帮助器方法为其返回false。我只需要定义了IEnumerable&lt;T&gt; 类型的实例返回true

我可能只是错过了一些相当明显的事情——谁能指出我正确的方向?

【问题讨论】:

  • 我不明白这个问题。很清楚为什么typeof() 任何类型都不会返回true;您是在问 type object 是否实现了接口,而不是类型本身。也许你想要IsAssignableFrom()?但是您认为string 的哪些方面不符合条件?它确实有“定义的IEnumerable&lt;T&gt; 类型”。
  • 是的,这就是类型一的问题——我整天都在研究类型和实例之间的反射嵌套,并且有点困惑! string 确实符合条件,但是在这种情况下,我确实需要排除它 - 在这个阶段可能更多的是方法命名问题。我想我会保持原样,然后添加另一个只对字符串进行检查的命令。
  • 同意@JeroenMostert ...“重复”是在询问一个类型是否正在使用反射实现IEnumerable&lt;x&gt;,这个是在询问一个类型是否正在实现IEnumerable,这是另一回事并且需要不同的解决方案(由不同的接受答案证明)
  • 也许你寻找的是ICollection&lt;x&gt;而不是IEnumerable&lt;x&gt;

标签: c# .net inheritance reflection types


【解决方案1】:

除了Type.IsAssignableFrom(Type),还可以使用Type.GetInterfaces()

public static bool ImplementsInterface(this Type type, Type interfaceType)
{
    // Deal with the edge case
    if ( type == interfaceType)
        return true;

    bool implemented = type.GetInterfaces().Contains(interfaceType);
    return implemented;
}

这样,如果您想检查多个接口,您可以轻松修改ImplementsInterface 以获取多个接口。

【讨论】:

    【解决方案2】:

    要检查某些类型是否实现了 IEnumerable不管 T,需要检查 GenericTypeDefinition。

    public static bool IsIEnumerableOfT(this Type type)
    {
        return type.GetInterfaces().Any(x => x.IsGenericType
               && x.GetGenericTypeDefinition() == typeof(IEnumerable<>));
    }
    

    【讨论】:

    • 小修正:在 type 本身是 typeof(IEnumerable&lt;T&gt;) 的边缘情况下失败,在某些情况下可能会出现静默失败:dotnetfiddle.net/vLFdHW -- 修复很容易,只需抛出一个.Append(type) 就在 .Any 之前,以便检查类型本身:dotnetfiddle.net/5wj1KE
    【解决方案3】:

    下面一行

    return (type is IEnumerable);
    

    在问“Typetype 的实例是否是 IEnumerable”,显然不是。

    你要做的是:

    return typeof(IEnumerable).IsAssignableFrom(type);
    

    【讨论】:

    • @Octopoid 一个字符串实现了IEnumerable&lt;char&gt;,所以这是真的,因为这就是你所要求的
    • @Octopoid 这是正确的行为。 string 是一个IEnumerable&lt;char&gt;,它是一个IEnumerable
    • @Octopoid 实际上如果你再检查它会更好!
    • 如果您出于某种原因排除了string,而没有看到您的代码或不知道要求,您可能也想排除许多可能的其他人(特别是如果您正在创建一个可以在未来的代码中由目前未知的类型使用)。我不明白为什么string 与许多其他可能的IEnumerables 不同。如果是这种情况,您最好明确说明您支持的内容,而不是使用“实施IEnumerable”作为检查
    • 我现在不明白为什么这是公认的答案。 IEnumerable 与 IEnumerable 不同,与 T 无关。可能存在仅实现 IEnumerable 的类型。
    猜你喜欢
    • 2021-04-15
    • 2016-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多