我正在.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();
}
答案 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<>