技术开发 频道

谈表达式树的缓存:二叉搜索树(AVL树)

    ExpressionComparer实现了IComparer<Expression>接口,可以进行两个表达式树的“大小”比较。从代码中可以看出,它的Compare方法与ExpressionVisitor的Visit方法很接近,起到了一个“中枢”的作用,会将调用“转发”给具体的CompareXxx方法进行比较。不过这么做的前提是两个表达式树的类型相同——更确切地说是两个表达式树从“外观”上来看并没有区别,所以才需要使用CompareXxx方法进行“深入”比较。从代码中可以看出,Compare深得比较之道,它会率先比较能够“立即”得到的信息,如果已经能够看出差距,便可快速地直接返回。为此,老赵在ExpressionComparer中还实现了一些比较特定类型用的辅助方法,摘录部分如下:

protected bool CompareNull<T>(T x, T y, out int result) where T : class
{
if (x == null && y == null)
{
result = 0;
return true;
}

if (x == null || y == null)
{
result = x == null ? -1 : 1;
return true;
}

result = 0;
return false;
}

protected virtual int CompareType(Type x, Type y)
{
if (x == y) return 0;

int result;
if (this.CompareNull(x, y, out result)) return result;

result = x.GetHashCode() - y.GetHashCode();
if (result != 0) return result;

result = x.Name.CompareTo(y.Name);
if (result != 0) return result;

return x.AssemblyQualifiedName.CompareTo(y.AssemblyQualifiedName);
}
 

    CompareNull方法比较两者是否为null,并根据情况给出大小关系。而CompareType方法则是比较两个Type类型的对象,从中也可以看出我们的比较策略:从最迅速的比较入手,“万不得已”才会比较相对低效的内容。因此在CompreType方法中,在大部分情况下就已经能够通过两个对象的Hash Code中得到它们的大小关系,只有在“万中无一”的情况下,两个不同的Type对象才会有相同的HashCode,那么我们再进行低效的字符串比较。这样的原则同样出现在各CompareXxx中,如CompareUnary:

protected virtual int CompareUnary(UnaryExpression x, UnaryExpression y)
{
int result = x.IsLifted.CompareTo(y.IsLifted);
if (result != 0) return result;

result = x.IsLiftedToNull.CompareTo(y.IsLiftedToNull);
if (result != 0) return result;

result = this.CompareMemberInfo(x.Method, y.Method);
if (result != 0) return result;

return this.Compare(x.Operand, y.Operand);
}
  而比较的“终点”则是ConstantExpression或ParameterExpression。其中CompareConstant方法实现如下:

protected virtual int CompareConstant(ConstantExpression x, ConstantExpression y)
{
return Comparer.Default.Compare(x.Value, y.Value);
}
 

    在这里使用Comparer.Default这个框架自带的默认比较器进行object的比较,其中会检查它们是否为字符串,或者实现了IComparable接口——如果不实现,则说明“无法进行比较”,于是会抛出异常。不过如果需要进行比较,那么这么做几乎是必须的,所以这点对于我们的使用来说并不成为问题,就不作处理了。需要补充的一点是:我们的比较方式其实是基于表达式树的遍历序列的,其比较方式其实与“字典序比较字符串”并没有多大差别,所以这种大小关系同样具备传递性。也就是说,如果Exp1 > Exp2且Exp2 > Exp3,则Exp1 > Exp3。

0
相关文章