我开发了一个MVC助手,用于生成显示和可编辑的表格(需要jquery插件才能允许在可编辑表格中动态添加和删除行,并进行完整的回传),例如:
@Htm.TableDisplayFor(m => m.MyCollection as ICollection)
使用该方法与属性结合,将在页脚包含总计信息,添加查看和编辑链接的列,为复杂类型呈现超链接等。例如:
[TableColumn(IncludeTotals = true)]
我即将在CodeProject上发布它,但在此之前,希望解决一个问题。助手首先从表达式中获取ModelMetadata,检查它是否实现了ICollection接口,然后获取集合中的类型(请注意下面的片段来自SO上的被接受答案,但正如下面所解释的那样,它并不完全正确)。
if (collection.GetType().IsGenericType)
{
Type type = collection.GetType().GetGenericArguments()[0]
该类型用于生成表头的
ModelMetadata
(该表可能没有任何行)以及表体中每一行的ModelMetadata
(如果某些项是继承类型,具有其他属性,否则会破坏列布局)。请注意保留HTML标记。foreach (var item in collection)
{
ModelMetadata itemMetadata = ModelMetadataProviders.Current
.GetMetadataForType(() => item, type);
我希望能够使用 IEnumerable
而不是 ICollection
,这样就不需要在LINQ表达式中调用.ToList()
方法。
在大多数情况下,IEnumerable
工作得很好,例如:
IEnumerable items = MyCollection.Where(i => i....);
可以正常运行,因为.GetGenericArguments()
返回只包含一个类型的数组。
问题是,某些查询中的'.GetGenericArguments()'返回2个或更多个类型,并且似乎没有逻辑顺序。例如:
IEnumerable items = MyCollection.OrderBy(i => i...);
返回 [0] 集合中的类型,[1] 用于排序的类型。
在这种情况下,.GetGenericArguments()[0]
仍然有效,但是
MyCollection.Select(i => new AnotherItem()
{
ID = i.ID,
Name = 1.Name
}
返回[0]原集合中的类型和[1]AnotherItem
的类型。
所以.GetGenericArguments()[1]
是我需要用来渲染AnotherItem
表格的。
我的问题是,是否有可靠的方法使用条件语句获取我需要渲染表格的类型?
到目前为止,根据我的测试,除了使用OrderBy()
时排序键是最后一个类型外,使用.GetGenericArguments().Last()
在所有情况下都有效。
我尝试过的一些方法包括忽略值类型的类型(因为在使用OrderBy()
时通常会出现),但是OrderBy()
查询可能会使用string
(可以检查),甚至更糟糕的是,类重载了==,<和>运算符(在这种情况下我将无法确定哪种是正确的类型),而且我找不到一种方法来测试集合是否实现了IOrderedEnumerable
。
IEnumerable<T>
,它是某个随意的LINQ查询结果(通常如此)。你想要可靠地获取IEnumerable<T>
的T
部分? - Chris SinclairIEnumerable<T>
接口并提取T
部分:var type = items.GetType().GetInterfaces().Where(t => t.IsGenericType).Where(t => t.GetGenericTypeDefinition() == typeof(IEnumerable<>)).Single().GetGenericArguments()[0];
注意我的使用Single
:如果接口未实现,则会失败,或者如果它实现了两个(或更多)不同的IEnumerable<T>
接口,则也会失败。您可以将其更改为使用FirstOrDefault
或First
并根据需要处理这些额外情况。 - Chris SinclairArrayList
是没有类型的。您可以提取第一个项并调用其GetType()
方法,但是如果它没有任何项,则无法判断。此外,这也不能保证您拥有一组混合对象,或者想要使用基类而不是GetType()
返回的派生类。如果您希望这样做,如果它没有实现IEnumerable<T>
(仅为IEnumerable
),则您可以将其视为类型object
? - Chris Sinclair