为什么Assembly.GetTypes()不能返回封闭泛型类型?
本文关键字:泛型类型 返回 不能 Assembly GetTypes 为什么 | 更新日期: 2023-09-27 18:18:24
我为自定义泛型类(TabularList<>
)创建了一个通用的JavaScriptConverter
派生,我将其称为ITabularConverter<>
。ITabularConverter
使用反射来检索从TabularList<>
泛型定义派生的所有封闭类型,以通知JavaScriptSerializer它能够转换ITabularConverter<>
的所有封闭类型。代码看起来像这样:
public override IEnumerable<Type> SupportedTypes
{
get
{
var type = typeof (TabularList<>);
var itabulars = Assembly.GetAssembly(type).GetTypes()
.Where(t => t.IsGenericType
&& t.GetGenericTypeDefinition() == type);
return itabulars;
}
}
问题是,尽管在执行这段代码时至少存在一个TabularList<>的封闭类型,但上面的代码只返回开放泛型类型定义。当我将搜索扩展到所有当前加载的程序集时,也是如此。
更奇怪的是,如果我检查调用堆栈,我可以看到JavaScriptSerializer。方法正在被调用,并使用即时窗口检查被序列化的对象,并证明存在泛型定义的封闭版本。然而,当我在即时窗口中执行以下代码时,结果是false
:
Assembly.GetAssembly(obj.TabularListProp.GetType())
.GetTypes()
.Contains(obj.TabularListProp.GetType());
因此,我检索定义了封闭泛型的程序集,然后在该程序集定义的类型中查找封闭泛型类型,但没有找到封闭类型。这怎么说得通呢?
下面是TabularList<>
的声明:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Serialization;
namespace Central.Claims.UX.ClaimWFMgrViewModel
{
[Serializable]
public class TabularList<T> : List<T>, ITabular
{
private List<List<object>> _tableView;
[XmlIgnore]
public List<List<object>> TableView
{
get { return GetTableView(); }
}
private List<KeyValuePair<string, Func<object, object>>> Schema { get; set; }
public TabularList()
{
Initialize();
}
public TabularList(IEnumerable<T> source) : base(source)
{
Initialize();
}
private void Initialize()
{
RefreshTableView = true;
var type = typeof(T);
if (Schemas.ContainsKey(type.Name))
{
Schema = Schemas[type.Name];
}
else
{
Schema = new List<KeyValuePair<string, Func<object, object>>>();
}
}
protected List<List<object>> GetTableView()
{
GetSchema();
BuildTable();
return _tableView;
}
private void GetSchema()
{
if (this.Any())
{
var properties = this.First().GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var property in properties)
{
var getter = property.GetGetMethod();
Schema.Add(new KeyValuePair<string, Func<object, object>>(
property.Name,
(Func<object, object>) Delegate.CreateDelegate(typeof (Func<object, object>), getter)
));
}
}
}
private void BuildTable()
{
_tableView = new List<List<object>>();
foreach (var item in this)
{
TableView.Add(ToTableRow(item));
}
}
private List<object> ToTableRow(T item)
{
var row = new List<object>();
foreach (var column in Schema)
{
row.Add(column.Value(item));
}
return row;
}
}
}
基于这里提供的答案,我在SO问题中重新表述了这个问题如何检索由。net运行时生成的所有封闭泛型类型的列表?
请记住,反射只是查询元数据,因此其中包含的任何信息都是纯编译类型的信息。拥有TabularList<SomeType>)
实例的事实并不会更改定义它的程序集中包含的元数据。
封闭泛型不是在定义开放泛型的程序集中定义的,也不是在创建该特定封闭类型的程序集中定义的。
您是否期望在mscorlib
中找到所有可能的 List<T>
封闭定义的元数据?您希望在创建List<int>
变量的程序集中找到它吗?
注意,的作用与相反——如果你调用
Assembly a = Assembly.GetAssembly(typeof(List<int>));
得到Assembly
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
因此,您可能能够逆转您的逻辑-而不是搜索程序集中的所有封闭类型,而是查找封闭类型的程序集,看看它是否"受支持"。
泛型类型通常不存在于程序集中。如果是这种情况,那么类型参数的每个可能的组合都需要出现,这将很快为您提供无限数量的不同类型。
因此,泛型类型定义是存在于程序集中的具体类型。您可以通过在类型上调用GetGenericTypeDefinition()
来获得泛型类型定义:
Type t = typeof(List<int>);
t.Assembly.GetTypes().Contains(t); // false
t.Assembly.GetTypes().Contains(t.GetGenericTypeDefinition()); // true