日期:2010-01-27  浏览次数:20421 次

我们看一下之前例子中的代码:<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"解析为表达式,最后以")"结束。