簡體   English   中英

如何檢查泛型類型T是否為IEnumerable <T'> 其中T&#39;未知

[英]How to check whether a Generic Type T is IEnumerable<T'> where T' is unkown

我寫了一個像這樣的擴展方法:

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

這是我編寫的一個測試程序 ,它顯示了它的全部功能(它測試類,結構和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>>它可能把太多,英寸,這第二個版本有一個檢查。

測試程序顯示如何使用此方法和String.Join一起使用。

您可以使用返回對象的非通用版本的IEnumerable

public static String Join(this IEnumerable enumerable)
{
    var enumerable2 = enumerable as IEnumerable<IEnumerable>;
    if (enumerable2 != null)
    {
        return String.Join(",", enumerable2.Select(e => e.Join()));
    }
    return String.Join(",", enumerable.Select(e => e.ToString()));
}

編輯:該方法不需要是通用的。 請注意字符串是IEnumerable,因此您可能想要添加一個特殊情況:

public static String Join(this IEnumerable enumerable)
{
    var stringEnumerable = enumerable as IEnumerable<string>;
    if (stringEnumerable != null)
    {
        return String.Join(",", stringEnumerable);
    }
    var enumerable2 = enumerable as IEnumerable<IEnumerable>;
    if (enumerable2 != null)
    {
        return String.Join(",", enumerable2.Select(e => e.Join()));
    }
    return String.Join(",", enumerable.Select(e => e.ToString()));
}

“檢查”部分沒有太大問題,但隨后對Join調用要求您提供Type參數。 因此,我發現的唯一解決方案是使用反射來進行調用。

完整的代碼如下(將類型參數檢索到IEnumerable<>的函數比這里需要的更通用,因為我只是從項目中復制並粘貼它):

    static public Type[] ListeTypeArgumentZuBaseOderInterface(
        this Type Type,
        Type BaseGenericTypeDefinition)
    {
        if (null == Type || null == BaseGenericTypeDefinition)
        {
            return null;
        }

        if (BaseGenericTypeDefinition.IsInterface)
        {
            var MengeInterface = Type.GetInterfaces();

            if (null != MengeInterface)
            {
                foreach (var Interface in MengeInterface)
                {
                    if (!Interface.IsGenericType)
                    {
                        continue;
                    }

                    var InterfaceGenericTypeDefinition = Interface.GetGenericTypeDefinition();

                    if (!InterfaceGenericTypeDefinition.Equals(BaseGenericTypeDefinition))
                    {
                        continue;
                    }

                    return Interface.GenericTypeArguments;
                }
            }
        }
        else
        {
            var BaseTypeAktuel = Type;

            while (null != BaseTypeAktuel)
            {
                if (BaseTypeAktuel.IsGenericType)
                {
                    var BaseTypeGenericTypeDefinition = BaseTypeAktuel.GetGenericTypeDefinition();

                    if (BaseTypeGenericTypeDefinition.Equals(BaseGenericTypeDefinition))
                    {
                        return BaseTypeAktuel.GenericTypeArguments;
                    }
                }

                BaseTypeAktuel = BaseTypeAktuel.BaseType;
            }
        }

        return null;
    }

    static public Type IEnumerableTypeArgumentExtrakt(
        this Type TypeImplementingEnumerable)
    {
        var GenericTypeArguments =
            ListeTypeArgumentZuBaseOderInterface(TypeImplementingEnumerable, typeof(IEnumerable<>));

        if (null == GenericTypeArguments)
        {
            //  does not implement IEnumerable<>
            return null;
        }

        return GenericTypeArguments.FirstOrDefault();
    }

    public static String Join<T>(this IEnumerable<T> enumerable)
    {
        //  ¡the typeof() has to refer to the class containing this Method!:
        var SelfType = typeof(Extension);

        var IEnumerableTypeArgument = IEnumerableTypeArgumentExtrakt(typeof(T));

        if (null != IEnumerableTypeArgument)
        {
            System.Reflection.MethodInfo method = SelfType.GetMethod("Join");
            System.Reflection.MethodInfo generic = method.MakeGenericMethod(IEnumerableTypeArgument);

            return String.Join(",", enumerable.Select(e => generic.Invoke(null, new object[] { e })));
        }

        return String.Join(",", enumerable.Select(e => e.ToString()));
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM