【发布时间】:2015-10-19 23:56:48
【问题描述】:
我为自定义泛型类 (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.Serialize 方法被调用的位置,并使用即时窗口检查正在序列化的对象并证明存在通用定义的封闭版本。然而,当我在即时窗口中执行以下代码时,结果是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 问题 How to retrieve a list of all closed generic types generated by the .NET runtime? 中重新表述了这个问题
【问题讨论】:
-
该类型是否存在于
TabularList<>类型所在的同一程序集中? -
发布您的班级声明,您确定
GetTypes不会返回吗?或者你的 where 条件过滤它?对于不带任何类型参数的类型,IsGenericType将为 false。 -
@DavidG - 不,类型是在同一解决方案的另一个项目中定义的,而这些代码 sn-ps 是在 Web 应用程序中。
-
@SriramSakthivel - 发布班级声明。在这种情况下,我只是使用
GetTypes().Contains(type)。当我最初发布问题时,我使用的是 Linq,但我切换到.Contains(),因为即时窗口无法处理 lambda 表达式。 -
Type.Assembly 属性的文档说:“如果当前 Type 对象表示构造的泛型类型,则此属性返回包含泛型类型定义的程序集。” Assembly.GetAssembly(Type) 方法的文档没有这样说,但它应该这样做,因为它做同样的事情。 (这只是糟糕的文档)
标签: c# .net generics reflection