Expression.ToString() 有效吗?
Does Expression.ToString() work?
我有一个生成的 lambda,但是当我想看它就像一个普通的 lambda 时,它只是不显示任何内容。当我打电话给 expr.Body.ToString()
时,我得到以下信息:
{var compareA; ... }
但是表达式的 DebugView 工作正常:
.Lambda #Lambda1<System.Comparison`1[XLinq.Test.Comparers.CustomComparerTest+Test]>(
XLinq.Test.Comparers.CustomComparerTest+Test $x,
XLinq.Test.Comparers.CustomComparerTest+Test $y) {
.Block(System.Int32 $compareA) {
$compareA = .Call ($x.A).CompareTo($y.A);
.If ($compareA != 0) {
.Return #Label1 { $compareA }
} .Else {
.Block(System.Int32 $compareB) {
$compareB = .Call ($x.B).CompareTo($y.B);
.If ($compareB != 0) {
.Return #Label1 { $compareB }
} .Else {
.Block(System.Int32 $compareC) {
$compareC = .Call ($x.C).CompareTo($y.C);
.If ($compareC != 0) {
.Return #Label1 { $compareC }
} .Else {
.Block(System.Int32 $compareD) {
$compareD = .Call ($x.D).CompareTo($y.D);
.If ($compareD != 0) {
.Return #Label1 { $compareD }
} .Else {
.Default(System.Void)
}
}
}
}
}
}
};
.Label
0
.LabelTarget #Label1:
}
}
为什么我会得到这个结果?
这是因为 Expression.ToString
覆盖依赖于内部 ExpressionStringBuilder
访问者类型,这会生成一个大大简化的表达式树表示。
每个 Expression
派生类型(即 BlockExpression
上的 [DebuggerTypeProxy(typeof(Expression.BlockExpressionProxy))]
)定义的自定义调试器代理提供的调试视图提供了更多信息,正如您所发现的,通过公开更详细的 DebugViewWriter
访问者(也是内部)的输出。
不幸的是,您无法在调试场景之外轻松获得该输出,除非您愿意使用反射来获取私有 DebugView
属性 的值(定义在 System.Linq.Expressions.Expression
) 如下:
Expression<Func<string, int>> expr = str => str.Length;
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
PropertyInfo debugViewProp = typeof(Expression).GetProperty("DebugView", flags);
MethodInfo debugViewGetter = debugViewProp.GetGetMethod(nonPublic: true);
string debugView = (string)debugViewGetter.Invoke(expr, null);
生产
.Lambda #Lambda1<System.Func`2[System.String,System.Int32]>(System.String $str) {
$str.Length
}
一如既往,Reference Source 是您最好的朋友:
我有一个生成的 lambda,但是当我想看它就像一个普通的 lambda 时,它只是不显示任何内容。当我打电话给 expr.Body.ToString()
时,我得到以下信息:
{var compareA; ... }
但是表达式的 DebugView 工作正常:
.Lambda #Lambda1<System.Comparison`1[XLinq.Test.Comparers.CustomComparerTest+Test]>(
XLinq.Test.Comparers.CustomComparerTest+Test $x,
XLinq.Test.Comparers.CustomComparerTest+Test $y) {
.Block(System.Int32 $compareA) {
$compareA = .Call ($x.A).CompareTo($y.A);
.If ($compareA != 0) {
.Return #Label1 { $compareA }
} .Else {
.Block(System.Int32 $compareB) {
$compareB = .Call ($x.B).CompareTo($y.B);
.If ($compareB != 0) {
.Return #Label1 { $compareB }
} .Else {
.Block(System.Int32 $compareC) {
$compareC = .Call ($x.C).CompareTo($y.C);
.If ($compareC != 0) {
.Return #Label1 { $compareC }
} .Else {
.Block(System.Int32 $compareD) {
$compareD = .Call ($x.D).CompareTo($y.D);
.If ($compareD != 0) {
.Return #Label1 { $compareD }
} .Else {
.Default(System.Void)
}
}
}
}
}
}
};
.Label
0
.LabelTarget #Label1:
}
}
为什么我会得到这个结果?
这是因为 Expression.ToString
覆盖依赖于内部 ExpressionStringBuilder
访问者类型,这会生成一个大大简化的表达式树表示。
每个 Expression
派生类型(即 BlockExpression
上的 [DebuggerTypeProxy(typeof(Expression.BlockExpressionProxy))]
)定义的自定义调试器代理提供的调试视图提供了更多信息,正如您所发现的,通过公开更详细的 DebugViewWriter
访问者(也是内部)的输出。
不幸的是,您无法在调试场景之外轻松获得该输出,除非您愿意使用反射来获取私有 DebugView
属性 的值(定义在 System.Linq.Expressions.Expression
) 如下:
Expression<Func<string, int>> expr = str => str.Length;
BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
PropertyInfo debugViewProp = typeof(Expression).GetProperty("DebugView", flags);
MethodInfo debugViewGetter = debugViewProp.GetGetMethod(nonPublic: true);
string debugView = (string)debugViewGetter.Invoke(expr, null);
生产
.Lambda #Lambda1<System.Func`2[System.String,System.Int32]>(System.String $str) {
$str.Length
}
一如既往,Reference Source 是您最好的朋友: