[译]Razor内幕之表达式
我们看一下之前例子中的代码:<li>@p.Name ($@p.Price)</li>是如何解析的。 当遇到"<li>"字符序列的时候,解析器知道正在解析一个以"</li>"为结束标志的标记。然后标记解析器在解析到结束标志之前发现了一个"@"字符,就像"@foreach"一样,再次切换到代码解析器。这时和之前的解析有些不同,C#代码解析器发现第一个标识符"p"时,它会检查这个标识符是不是C#的关键字;当然"p"并不是C#关键字,所以代码解析器进入"隐式表达式"模式。解析隐式表达式的算法看起来是这样的:
-
首先读取一个标识符,
-
下一个字符是"("或者"["?
-
是则读到匹配的")"或者"]",然后跳到2
-
不是则继续3
-
-
下一个字符是"."?
-
是则继续4
-
不是则结束表达式
-
-
"."后面的字符是合法的C#标识符的开始?
-
是则读取"."并跳到1
-
不是则不读"."并结束表达式
-
总体来说就是:一个隐式表达式就是一个标识符,之后可以跟任意数量的方法调用("()")、索引表达式("[]")及成员访问表达式(".")。但是,除了在"()"或者"[]"里面,是不允许空格存在的。例如,下面是一些合法的Razor隐式表达式:
@p.Name
@p.Name.ToString()
@p.Name.ToString()[6 - 2]
@p.Name.Replace("ASPX", "Razor")[i++]
下面是一些非法的表达式,这些表达式只有部分("==>"之后的部分)会被Razor认为是表达式。
@1 + 1 ==> @
@p++ ==> @p
@p . Name ==> @p
@p.Name.Length – 1 ==> @p.Name.Length
这是我们为什么需要另一个表达式语法:"@(...)"的原因,通过这个语法我们可以把任何想要的东西放到"()"里面,上面的例子用这个语法来表示就是:
@(1 + 1)
@(p++)
@(p . Name)
@(p.Name.Length - 1)
一旦我们验证了表达式,我们会把它传递到代码生成器中。当为"@foreach () { … }"生成代码的时候,会把代码写到生成的C#类文件中。对于表达式(无论是显示的或者是隐式的)来说,这个过程有一点不同,不像ASPX,这里只有一个控制结构"@",并没有"@="来区分运行代码和要输出值的表达式,但这也是Razor的魅力所在。例如,当发现"@foreach"的时候,我们知道"foreach"是C#中的一个关键字,所以这个块会被作为声明来执行;而发现"@p.Name"或者"@(1 + 1)"的时候,我们知道它们是表达式,所以在执行这些语句之后输出了执行结果。
总之:
@if, @switch, @try, @foreach, @for, 等是和"<% %>"一样的
@p.Name, @(p++), @(1 + 1),等是和"<%: %>"一样的
另一个需要注意的地方就是表达式等同于"<%:"而不是"<%=""。在Razor中默认应该进行HTML Encode处理,如果不想进行HTML Encode处理,可以使用IHtmlString接口。
知道解析原理之后,下面我们再回到之前的代码:
<li>@p.Name ($@p.Price)</li>
当发现"@p.Name"之后,可以识别出这是一个表达式,通过"("字符之前的空格解析出这不是一个方法调用,之后是文本标记""($",然后再次发现"@"之后将"@p.Price"解析为表达式,最后以")"结束。
查看下一篇:Razor内幕之模板
查看原文,点击此处。
注:如果发现有翻译不恰当或者疏漏的地方请反馈给我,我会及时更正,谢谢!
本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名孙镜涛(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言。