问题描述
我在使用 asp.net MVC razor 视图时遇到了一个奇怪的问题.
I'm having an odd problem with asp.net MVC razor view.
我希望我的模型是一个 List
@model
声明中时,它似乎只选择了元组的字符串部分.所以我没有整数.只有第 1 项.
I want my model to be a List<Tuple<string, int, int, int, int>>
which is perfectly valid in my other c# methods. But when I paste it into the @model
declaration it seems to only pick out the string part of the tuple. So I have no ints. Only item1.
如果我将其绑定到元组而不是列表,则不会出现此问题.
This problem is not present if I make it bind to a Tuple instead of the List.
好像生成的代码是错误的,所以也许这是剃刀视图中的一个错误?
Seems like the generated code is wrong, so perhaps this is a bug in razor view?
我在编译时遇到的错误是:
The error I get at compilation is:
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.
Compiler Error Message: CS1003: Syntax error, '>' expected
Source Error:
Line 27:
Line 28:
Line 29: public class _Page_Views_Dashboard_DestinationStatistics_cshtml : System.Web.Mvc.WebViewPage<List<Tuple<string {
Line 30:
Line 31: #line hidden
为了隔离这个问题,我做了以下事情:
To isolate this problem I did the following thing:
创建一个空的 asp.net mvc 项目.创建一个新视图.通过以下代码.
Create an empty asp.net mvc project. Create a new view. Past the following code.
@model List<Tuple<string, int, int, int, int>>
@foreach (var stat in Model)
{
<tr>
<td>
@stat.Item1
</td>
<td>
@stat.Item2
</td>
<td>
@stat.Item3
</td>
<td>
@stat.Item4
</td>
<td>
@stat.Item5
</td>
</tr>
}
我知道我可以只创建一个类或结构来保存数据.只是好奇问一下
I know I can just create a class or a struct to hold the data instead. Just asking out of curiosity
在这里解决并报告给MVC团队http://aspnet.codeplex.com/workitem/8652
Solved and reported to the MVC team here http://aspnet.codeplex.com/workitem/8652
推荐答案
编辑 我已经删除了一些正在进行的评论 - 只需查看历史记录即可.
因此,您可以使用 1、2、3 或 4 个元组泛型参数使其工作,但它不适用于 5.一旦使用 5 个参数,它就会生成如下代码:
So you can make this work with 1, 2, 3 or 4 tuple generic parameters but it doesn't work with 5. As soon as you use 5 parameters it generates code like this:
public class _Page_Views_Home_Index_cshtml :
System.Web.Mvc.WebViewPage<List<System.Tuple<string {
我想知道它是否是字符长度限制,所以我生成了一个这样的类:
I wanted to just find out if it's a character-length limitation, so I generated a class like this:
namespace ASP{ //same namespace that the backend code for the page is generated
public class T { }
}
并更改了模型声明:
@model List<Tuple<T,T,T,T,T>>.
最后(见历史)我得到了
In the end (see the history) I got to
@inherits System.Web.Mvc.WebViewPage<Tuple<T,T,T,T,T>>
同样的问题!@model 关键字不是问题...
Same problem! It's not a problem with the @model keyword...
花了一些时间(阅读 MVC3 和 Razor 源代码,为该解决方案添加了几个测试) - 但这里有一个测试说明了我们为什么会收到此错误:
It took a while (reading through the MVC3 and Razor source, adding a couple of tests to that solution) - but here's a test that shows the why we get this error:
[TestMethod]
public void TestMethod()
{
System.CodeDom.CodeTypeReferenceCollection c =
new CodeDom.CodeTypeReferenceCollection();
c.Add("Tuple<T,T,T,T>");
c.Add("Tuple<T,T,T,T,T>");
//passes
Assert.AreEqual("Tuple<T,T,T,T>", c[0].BaseType);
//fails
Assert.AreEqual("Tuple<T,T,T,T,T>", c[1].BaseType);
}
所以 - 四参数版本通过,但不是 5 参数版本.
So - the four-parameter version passes, but not the 5 parameter version.
猜猜看 - 实际值是 Tuple
And guess what- the actual value is Tuple<T
- i.e. a truncated generic type name truncated exactly the same way that you've observed in your code.
标准 Razor 解析器和 Mvc Razor 解析器在解析 @inherits
或 @model
关键字时都使用 CodeTypeReferenceCollection
类型.以下是代码生成期间 @inherits
的代码:
Both the standard Razor parser and the Mvc Razor parser use the CodeTypeReferenceCollection
type when parsing either the @inherits
or @model
keyword. Here's the code for @inherits
during code generation:
protected internal virtual void VisitSpan(InheritsSpan span) {
// Set the appropriate base type
GeneratedClass.BaseTypes.Clear();
GeneratedClass.BaseTypes.Add(span.BaseClass);
if (DesignTimeMode) {
WriteHelperVariable(span.Content, InheritsHelperName);
}
}
GeneratedClass.BaseTypes
是 CodeTypeReferenceCollection
- span.BaseClass
是字符串.在 ILSpy 之后,违规方法必须是私有方法 CodeTypeReference.Initialize(string typeName, CodeTypeReferenceOptions options)
.我现在没有足够的时间来弄清楚它为什么会中断 - 但那是我认为 Microsoft 开发人员的工作 :) 下面的更新 - 无法抗拒.我现在知道哪里错了
GeneratedClass.BaseTypes
is a CodeTypeReferenceCollection
- and span.BaseClass
is a string. Following that through in ILSpy, the offending method must be the private method CodeTypeReference.Initialize(string typeName, CodeTypeReferenceOptions options)
. I've not enough time now to figure out why it breaks - but then that's a Microsoft developer's job I think :) Update below - couldn't resist. I now know where it's wrong
您不能在 Razor @inherits
或 @model
语句中使用超过 4 个参数的泛型(至少在 C# 中 - 不了解 VB).Razor 解析器似乎错误地使用了 CodeTypeReference
类型.
You can't use generics with more than 4 parameters in either Razor @inherits
or @model
statements (at least in C# - don't know about VB). It appears that the Razor parser is incorrectly using the CodeTypeReference
type.
CodeTypeReference
所做的一件事是通过调用 CodeTypeReference.RipOffAssemblyInformationFromTypeName(string typeName)
方法从传递的类型名称中去除程序集名称信息.
One of the things that CodeTypeReference
does is strip off assembly name information from a passed type name with a call to the method CodeTypeReference.RipOffAssemblyInformationFromTypeName(string typeName)
.
当然,如果您考虑一下 - Tuple
元组
T
,Version=T
,Culture=T
,PublicKeyToken=T
(如果你写了一个非常糟糕的 C# 解析器!).
And of course, if you think about it - Tuple<T,T,T,T,T>
is just like an assembly-qualified type name: With the type name = Tuple<T
, Assembly = T
, Version=T
, Culture=T
, PublicKeyToken=T
(if you write a really BAD C# parser!).
果然 - 如果你传入 Tuple
Tuple<T,T>代码>.
Sure enough - if you pass in Tuple<T,T,T,T,T,T>
as the type name - you actually get a Tuple<T,T>
.
深入研究代码,它已准备好接收与语言无关的类型名(例如,处理 '[' 但没有处理 '<')因此,实际上,MVC 团队不应该只处理 C# 类型名从我们的源头直通.
Looking deeper into the code, it's primed to receive a language-neutral typename (handles '[' but nothing for '<', for example) so, actually, the MVC team shouldn't just be handing the C# typename from our source straight through.
MVC 团队需要改变他们生成基本类型的方式 - 他们可以使用 public CodeTypeReference(string typeName, params CodeTypeReference[] typeArguments)
构造函数用于新引用(而不是仅仅依赖于 .Add(span.BaseClass)
创建它),并自己解析泛型参数,因为它们知道类型名称将是 C#/VB 风格 - 不是语言中立的 .Net 风格,带有括号等作为实际名称的一部分.
The MVC team needs to change how they generate the base type - They could use the public CodeTypeReference(string typeName, params CodeTypeReference[] typeArguments)
constructor for a new reference (instead of just relying on the .Add(span.BaseClass)
creating it), and parse the generic parameters themselves since they know that the type name will be C#/VB style - not language-neutral .Net style with brackets etc as part of the actual name.
这篇关于asp.net mvc 3 剃刀视图->强类型元组列表问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!