获取ICollection的类型参数<t>实现类</t>

时间:2012-12-05 08:21:44

标签: c# .net generics reflection

我正在.net中编写一个小的序列化库。目标是替换XmlSerialize,但更容易配置,而不会使模型与属性混淆。

我面临的问题是我需要在遍历模型时找到的每个ICollection<T>的类型。 天真的方法是:

 var theType=myModel.GetType().GetGenericArguments()[0];

但是对于使用特定T从ICollection<T>派生的类没有帮助。

public class MyClass:A,ICollection<B>{}

我尝试使用反射

获取界面
  var iCollectionInterface =
  o.GetType().GetInterfaces()
     .Where(i => i.IsGenericType)
     .Select(i => i.GetGenericTypeDefinition())
     .FirstOrDefault(i => i == typeof(ICollection<>));

iCollectionInterface.GetGenericArguments()[0]只是T,而不是B,因为它只描述了界面的定义而不是它的用法。

有什么想法吗?我也需要它IDictionary<TKey, TValue>,但这基本上是同一个问题,并且会有相同的解决方案。

谢谢!

修改

谢谢大家,这就是我最终的目标:

public static Type GetTypeParameter(object o, Type typeToSearch, int argumentNumber)
{
    return o.GetType()
            .GetInterfaces()
            .Where(i => i.IsGenericType)
            .Where(i => i.GetGenericTypeDefinition() == typeToSearch)
            .Select(t => t.GetGenericArguments()[argumentNumber])
            .FirstOrDefault();
}

3 个答案:

答案 0 :(得分:2)

这就是您所需要的:Type.GetGenericArguments Method

所以,有了

class MyDictionary: IDictionary<string, decimal>
{
    ...
}

试试这个扩展方法:

public static Type[] GetClosingArguments<T>(this Type type)
{
    Type iType = typeof(T).GetInterfaces()
                          .FirstOrDefault(i => i.IsGenericType &&
                                     i.GetGenericTypeDefinition() == type);
    if (iType == null)
        return null;
    else
        return iType.GetGenericArguments();
}
像这样

Type[] types = typeof(IDictionary<,>).GetClosingArguments<MyDictionary>();
if (types != null)
{
    foreach (Type t in types)
        Console.WriteLine(t.Name);
}

反之亦然:

public static Type[] GetClosingArguments(this Type type, Type baseGenericType)
{
    Type iType = type.GetInterfaces()
                     .FirstOrDefault(i => i.IsGenericType &&
                               i.GetGenericTypeDefinition() == baseGenericType);
    if (iType == null)
        return null;
    else
        return iType.GetGenericArguments();
}

称为

Type[] types = typeof(MyDictionary).GetClosingArguments(typeof(IDictionary<,>));

答案 1 :(得分:2)

从评论中看来,您需要弄清楚如何过滤集合以仅包含ICollection。您可以通过以下方式实现这一目标:

var iCollectionInterfaces =
      from i in o.GetType().GetInterfaces()
      where i.IsGenericType 
            && i.GetGenericTypeDefinition() == typeof(IColection<>)
      select i;

然后,您可以遍历集合并对每个类型参数执行任何操作

//same type might implement ICollection<T> more than once
foreach(var collection in iCollectionInterfaces) {
     //More than one is invalid for ICollection<T>
    var T = collection.GetGenericArguments().Single();
    //do what ever you need
}

当然,如果你想让它更通用。即支持具有多个类型参数的接口/类型,您需要删除对Single的调用并替换类型参数的迭代

答案 2 :(得分:0)

我认为以下调用是问题

.Select(i => i.GetGenericTypeDefinition())

使用已定义泛型参数的闭合泛型类型,然后获得其通用定义,该定义是开放的,只知道T。也许您还需要更改FirstOrDefault来电,我不确定封闭类型是否等于ICollection<>