3

我正在.net 中编写一个小的序列化库。目标是替代 XmlSerialize,但更易于配置,并且不会用属性弄乱模型。

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

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

ICollection<T>但它对派生自特定 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<>));

but iCollectionInterface.GetGenericArguments()[0]is just 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();
}
4

3 回答 3

2

这就是您需要的:Type.GetGenericArguments 方法

所以,有

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<,>));
于 2012-12-05T08:29:04.990 回答
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并替换为类型参数的迭代

于 2012-12-05T09:31:46.877 回答
0

我认为以下电话是问题所在

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

您采用已定义泛型参数的封闭泛型类型,然后获得其泛型定义,它是开放的并且只知道T. 也许您还需要更改FirstOrDefault呼叫,我不确定封闭类型是否等于ICollection<>

于 2012-12-05T08:28:29.917 回答