我开发了一个用于生成显示和可编辑表的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
(表中可能没有任何行)和表体中的每一行(如果某些项是具有附加属性的继承类型,则会否则搞砸列布局)
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
呈现表格所需要的。
我的问题是,是否有一种可靠的方法使用条件语句来获取表格所需的类型?
到目前为止,我的测试中使用.GetGenericArguments().Last()
在所有情况下均有效,除非使用OrderBy()
,因为排序键是最后一种类型。
到目前为止我尝试过的一些事情包括忽略值类型的类型(OrderBy()
通常会出现这种情况,但OrderBy()
查询可能会使用string
(其中可以检查)或更糟糕的是,一个超载==,<和>运算符的类(在这种情况下我无法分辨哪个是正确的类型),而我一直无法找到测试的方法如果集合实现IOrderedEnumerable
。
答案 0 :(得分:4)
已解决(使用Chris Sinclair发布的评论)
private static Type GetCollectionType(IEnumerable collection)
{
Type type = collection.GetType();
if (type.IsGenericType)
{
Type[] types = type.GetGenericArguments();
if (types.Length == 1)
{
return types[0];
}
else
{
// Could be null if implements two IEnumerable
return type.GetInterfaces().Where(t => t.IsGenericType)
.Where(t => t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.SingleOrDefault().GetGenericArguments()[0];
}
}
else if (collection.GetType().IsArray)
{
return type.GetElementType();
}
// TODO: Who knows, but its probably not suitable to render in a table
return null;
}