c# - 如何检查通用类型 T 是否为 IEnumerable<T'>,其中 T' 未知

标签 c# generics extension-methods

我写了一个这样的扩展方法:

public static String Join<T>(this IEnumerable<T> enumerable)
{
    if (typeof(T) is IEnumerable<T'> where T' is unknown at compile time)
    {
        return String.Join(",", enumerable.Select(e => e.Join()));
    }
    return String.Join(",", enumerable.Select(e => e.ToString()));
}

问题是我不知道如何在 if 语句中编写代码以使其工作。 有什么建议吗?谢谢!

最佳答案

因为您只调用了 .ToString()你实际上并不真正关心 T 是什么,只要它实现了 IEnumerable或不。以下是如何在没有反射的情况下仅使用 IEnumerable 来做到这一点而不是 IEnumerable<T> , 我为 String.Join 做我自己的逻辑因为它使编写递归逻辑代码变得更容易。

internal static class ExtensionMethods
{
    public static String Join<T>(this IEnumerable<T> enumerable)
    {
        StringBuilder sb = new StringBuilder();
        JoinInternal(enumerable, sb, true);
        return sb.ToString();
    }

    private static bool JoinInternal(IEnumerable enumerable, StringBuilder sb, bool first)
    {
        foreach (var item in enumerable)
        {
            var castItem = item as IEnumerable;
            if (castItem != null)
            {
                first = JoinInternal(castItem, sb, first);
            }
            else
            {
                if (!first)
                {
                    sb.Append(",");
                }
                else
                {
                    first = false;
                }

                sb.Append(item);
            }
        }
        return first;
    }
}

Here is a test program我写的显示一切正常(它测试类、结构和 IEnumerables 3 层深)。

编辑:根据您在这里的评论,这是另一个版本,它可以展平嵌套的 IEnumerables,您可以在完成后对每个元素做任何您想做的事情。

internal static class ExtensionMethods
{
    public static IEnumerable<T> SelectManyRecusive<T>(this IEnumerable enumerable)
    {
        foreach (var item in enumerable)
        {
            var castEnumerable = item as IEnumerable;
            if (castEnumerable != null 
                && ((typeof(T) != typeof(string)) || !(castEnumerable is string))) //Don't split string to char if string is our target
            {
                foreach (var inner in SelectManyRecusive<T>(castEnumerable))
                {
                    yield return inner;
                }
            }
            else
            {
                if (item is T)
                {
                    yield return (T)item;
                }
            }
        }
    }
}

我还遇到了一个错误,我认为它可能会影响我回答的第一部分,string技术上是 IEnumerable<char>所以IEnumerable<string>也可以被视为 IEnumerable<IEnumerable<char>>它可能会放太多 , in。第二个版本对此进行了检查。

Test program显示如何使用此方法和 String.Join在一起。

关于c# - 如何检查通用类型 T 是否为 IEnumerable<T'>,其中 T' 未知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29718343/

相关文章:

c# - 在 WinSCP .NET 程序集中包含和排除文件掩码

c# - 使用 Entity Framework 添加多个对象时如何获取多个对象的标识?

generics - 指定泛型参数属于一小组类型

c# - 我应该如何调用重载的扩展方法?

c# - 将方法添加到另一个项目的类

c# - 如何生成 "human readable"字符串来表示 TimeSpan

c# - 如何避免对 UserControl 的引用进行硬编码?

c# - Linq-to-entities、泛型和预编译查询

java - 带有泛型参数的单例

C# - 返回枚举?来自静态扩展方法