检查传递的对象是 IEnumerable<T> 还是单个值 - 包括 T 是值类型

Check if the object passed is IEnumerable<T> or a single value - Including T being a value types

在我的 C# 代码的一部分中,我使用了以下代码来检查传入的对象是单个值还是实现了 IEnumerable<T>T 是字符串、双精度、整数、等 - 绝不是复杂的对象或 class) :

Type type = paramValue.GetType();
if (type != typeof(string) && typeof(System.Collections.IEnumerable).IsAssignableFrom(type))
{
    var underlyingType = ((System.Collections.IEnumerable)paramValue).GetType().GetGenericArguments()[0];
}

它在所有情况下都运行良好,直到今天我通过了 int[],因为我发现这是一个问题 here

那么,获取同时考虑值类型的 IEnumerable 的基础类型的最佳方法是什么?

谢谢!!

一个 IEnumerable 没有基础类型 ,至少 object 没有。您知道序列中的每一项都是一个 object,但除此之外您一无所知。如果您想处理所有这些项目都属于同一类型的项目序列(该类型不是 object,那么您需要使用 IEnumerable<T>,而不是 IEnumerable

实际上,任何给定的 IEnumerable 都可能有一个字符串和一个 int 以及一个自定义对象,所有这些都在相同的序列中,所以 除了 object.

之外没有常见的类型

您想知道类型,如果它是 IEnumerable<T>(!= string) 您想要 T?对于数组,您可以使用 Type.GetElementType:

public static Type GetUnderlyingType(object paramValue)
{
    Type type = paramValue.GetType();
    var stringType = typeof(string);
    if (type == stringType)
        return stringType;
    else if (type.IsArray)
        type = type.GetElementType();
    else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type))
    {
        var genericArguments = ((System.Collections.IEnumerable) paramValue).GetType().GetGenericArguments();
        if(genericArguments.Length > 0)
            type = genericArguments[0];
    }
    return type;
}

正如@Servy所说,一个非泛型IEnumerable序列可能包含几种不同类型的元素。

如果您只关心序列中的第一个项目并假设所有其他项目都是同一类型,您可以尝试这样的事情:

int[] paramValue = new int[] { 1, 2, 3 };
Type type = paramValue.GetType();
Type underlyingType;
if (type != typeof(string))
{
    System.Collections.IEnumerable e = paramValue as System.Collections.IEnumerable;
    if(e != null)
    {
        Type eType = e.GetType();
        if(eType.IsGenericType)
        {
            underlyingType = eType.GetType().GetGenericArguments()[0];
        }
        else
        {
            foreach(var item in e)
            {
                underlyingType = item.GetType();
                break;
            }
        }
    }
}

请注意,例如,对于以下 paramValueunderlyingType 将是 int

object[] paramValue = new object[] { 1, "a", "c" };