我们知道页面引擎尤其是Razor的核心是如何对页面上的代码的解析。
而其中的核心的是一个语法解析树中的定位应该改变也算是非常频繁的操作。
对于其中关键的LocateOwner函数真的令我疑惑。
简单说明一下Razor中的语法树。Razor源码中是这样定义的。
基本机构,由上图可以知道。
Block就是一个集合,可以看成是一篇文章或一个句子,span就是具体表达的一个小块。
其中Block 提供了一个为'变动'提供定位span的方法。
/// <summary>
/// 定位改变所属的 块
/// </summary>
/// <param name="change"></param>
/// <returns></returns>
public Span LocateOwner(TextChange change) {
// Ask each child recursively
Span owner = null;
foreach (SyntaxTreeNode element in Children) {
Span span = element as Span;
if (span == null) {
owner = ((Block)element).LocateOwner(change);//如果是块则递归往下找
}
else {
if (change.Position < span.Start.AbsoluteIndex) {//超出-属于span
// Early escape for cases where changes overlap multiple spans
// In those cases, the span will return false, and we don't want to search the whole tree
// So if the current span starts after the change, we know we've searched as far as we need to
break;
}
owner = span.OwnsChange(change) ? span : owner;//deph
}
if (owner != null) {//是否已经得到答案
break;
}
}
return owner;
}
//再给出span.OwnsChange(change) 的源码
/// <summary>
/// Determines if the specified change belongs to this span.
/// </summary>
/// <remarks>
/// Used for Partial Parsing to identify which span to augment with the specified change.
/// Some changes have no owner, because they overlap multiple spans.
/// Also, just because a span owns a change, doesn't mean it can accept it
/// </remarks>
public virtual bool OwnsChange(TextChange change) {
int changeOldEnd = change.Position + change.OldLength;
return change.Position >= Start.AbsoluteIndex &&
(changeOldEnd < EndIndex || (changeOldEnd == EndIndex && CanGrow));
}
/// 定位改变所属的 块
/// </summary>
/// <param name="change"></param>
/// <returns></returns>
public Span LocateOwner(TextChange change) {
// Ask each child recursively
Span owner = null;
foreach (SyntaxTreeNode element in Children) {
Span span = element as Span;
if (span == null) {
owner = ((Block)element).LocateOwner(change);//如果是块则递归往下找
}
else {
if (change.Position < span.Start.AbsoluteIndex) {//超出-属于span
// Early escape for cases where changes overlap multiple spans
// In those cases, the span will return false, and we don't want to search the whole tree
// So if the current span starts after the change, we know we've searched as far as we need to
break;
}
owner = span.OwnsChange(change) ? span : owner;//deph
}
if (owner != null) {//是否已经得到答案
break;
}
}
return owner;
}
//再给出span.OwnsChange(change) 的源码
/// <summary>
/// Determines if the specified change belongs to this span.
/// </summary>
/// <remarks>
/// Used for Partial Parsing to identify which span to augment with the specified change.
/// Some changes have no owner, because they overlap multiple spans.
/// Also, just because a span owns a change, doesn't mean it can accept it
/// </remarks>
public virtual bool OwnsChange(TextChange change) {
int changeOldEnd = change.Position + change.OldLength;
return change.Position >= Start.AbsoluteIndex &&
(changeOldEnd < EndIndex || (changeOldEnd == EndIndex && CanGrow));
}
这里很明显可以看到作者采用深度优先的策略,这不是很奇怪吗?为什么不采用广度优先?
不是更容易定位吗?难道我又错了?想到半夜都没想通。大家说说看。