如何检测对象是否为通用集合,以及它包含哪些类型?

Sha*_*ica 10 c# generics typechecking

我有一个字符串序列化实用程序,它接受(几乎)任何类型的变量并将其转换为字符串.因此,例如,根据我的惯例,整数值123将被序列化为"i:3:123"(i =整数; 3 =字符串的长度; 123 =值).

该实用程序处理所有原始类型,以及一些非泛型集合,如ArrayLists和Hashtables.界面是这种形式

public static string StringSerialize(object o) {}

在内部我检测对象是什么类型并相应地序列化它.

现在我想升级我的实用程序来处理泛型集合.有趣的是,我找不到一个合适的函数来检测对象是一个泛型集合,它包含哪些类型 - 我需要哪些信息才能正确序列化.到目前为止,我一直在使用表单的编码

if (o is int) {// do something}

但这似乎不适用于泛型.

您有什么推荐的吗?


编辑:感谢Lucero,我已经接近答案了,但我仍然坚持这个小小的语法难题:

if (t.IsGenericType) {
  if (typeof(List<>) == t.GetGenericTypeDefinition()) {
    Type lt = t.GetGenericArguments()[0];
    List<lt> x = (List<lt>)o;
    stringifyList(x);
  }
}
Run Code Online (Sandbox Code Playgroud)

此代码无法编译,因为" lt"不允许作为对象的<T>参数List<>.为什么不?什么是正确的语法?

Luc*_*ero 7

使用"类型"收集所需信息.

对于通用对象,调用GetType()以获取其类型,然后检查IsGenericType以确定它是否是通用的.如果是,你可以得到泛型类型定义,它可以例如像这样进行比较:typeof(List<>)==yourType.GetGenericTypeDefinition().要找出泛型类型是什么,请使用该方法GetGenericArguments,该方法将返回所使用类型的数组.

要比较类型,您可以执行以下操作:if (typeof(int).IsAssignableFrom(yourGenericTypeArgument)).


编辑回答后续行动:

只是让你的stringifyList方法接受一个IEnumerable(不是通用的)参数,也可能是已知的泛型类型参数,你会没事的; 然后,您可以foreach根据类型参数查看所有项目并根据需要进行处理.


Mar*_*ell 6

重新解决你的难题; 我假设stringifyList是一种通用方法?您需要使用反射调用它:

MethodInfo method = typeof(SomeType).GetMethod("stringifyList")
            .MakeGenericMethod(lt).Invoke({target}, new object[] {o});
Run Code Online (Sandbox Code Playgroud)

其中{target}null用于一个静态方法,或this用于在当前实例的实例方法.

进一步 - 我不会假设所有集合都是:基于List<T>,b:泛型类型.重要的是:他们是否实施IList<T>了一些T

这是一个完整的例子:

using System;
using System.Collections.Generic;
static class Program {
    static Type GetListType(Type type) {
        foreach (Type intType in type.GetInterfaces()) {
            if (intType.IsGenericType
                && intType.GetGenericTypeDefinition() == typeof(IList<>)) {
                return intType.GetGenericArguments()[0];
            }
        }
        return null;
    }
    static void Main() {
        object o = new List<int> { 1, 2, 3, 4, 5 };
        Type t = o.GetType();
        Type lt = GetListType(t);
        if (lt != null) {
            typeof(Program).GetMethod("StringifyList")
                .MakeGenericMethod(lt).Invoke(null,
                new object[] { o });
        }
    }
    public static void StringifyList<T>(IList<T> list) {
        Console.WriteLine("Working with " + typeof(T).Name);
    }
}
Run Code Online (Sandbox Code Playgroud)