替换部分 BlockExpression
Replace part of BlockExpression
这是一个块表达式
var compareTo = GetCompareToExpression<TProperty>(expression, parameters);
var compareToVariable = compareTo.Key;
var compareToCall = compareTo.Value;
var zero = Expression.Constant(0, typeof (int));
LabelTarget ret = Expression.Label(typeof (int));
var block = Expression.Block(new[] {compareToVariable},
Expression.Assign(compareToVariable, compareToCall),
Expression.IfThen(Expression.NotEqual(compareToVariable, zero),
Expression.Return(ret, compareToVariable)),
Expression.Label(ret, zero));
return block;
及其调试视图:
.Block(System.Int32 $compareItem1) {
$compareItem1 = .Call ($x.Item1).CompareTo($y.Item1);
.If ($compareItem1 != 0) {
.Return #Label1 { $compareItem1 }
} .Else {
.Default(System.Void)
};
.Label
0
.LabelTarget #Label1:
}
现在我需要用另一种方法中的一些自定义逻辑替换 .Default(System.Void)
。最简单的方法是什么?
Expression
是不可变的,就像 string
一样。要修改它们,您可以使用所需的更改创建它们的副本。通常你使用 ExpressionVisitor 的子类来完成它,比如:
public class DefaultVoidExpressionReplacer : ExpressionVisitor
{
public Expression To;
protected override Expression VisitDefault(DefaultExpression node)
{
if (node.Type == typeof(void))
{
return this.Visit(To);
}
else
{
return base.VisitDefault(node);
}
}
}
你可以像这样使用它:
var newExpression = new DefaultVoidExpressionReplacer
{ To = replaceExpression }.Visit(yourExpression);
您甚至可以决定在 "higher" 级别上工作:Expression.IfThen
级别:
protected override Expression VisitConditional(ConditionalExpression node)
{
DefaultExpression de = node.IfFalse as DefaultExpression;
if (de != null && de.Type == typeof(void))
{
return base.Visit(Expression.IfThenElse(node.Test, node.IfTrue, To));
}
return base.VisitConditional(node);
}
因为 BlockExpression
不允许你就地改变它(它的 Expressions
属性 是类型 ReadOnlyCollection<Expression>
,防止可能的修改)你需要建立一个旧块的新块。
表达式访问者提供了一种简单的编码方式:
class DefaultReplacer : ExpressionVisitor {
protected override Expression VisitGoto(GotoExpression g) {
if (g.Kind != GotoExpressionKind.Return || g.Value == null) {
return base.VisitGoto(g);
}
// If we are here, it's a return expression with Value.
// Check if Value represents default(System.Void),
// and return a replacement expression here
return ...
}
}
按如下方式使用此访客:
Expression modifiedBlock = block.Visit(new DefaultReplacer());
这是一个块表达式
var compareTo = GetCompareToExpression<TProperty>(expression, parameters);
var compareToVariable = compareTo.Key;
var compareToCall = compareTo.Value;
var zero = Expression.Constant(0, typeof (int));
LabelTarget ret = Expression.Label(typeof (int));
var block = Expression.Block(new[] {compareToVariable},
Expression.Assign(compareToVariable, compareToCall),
Expression.IfThen(Expression.NotEqual(compareToVariable, zero),
Expression.Return(ret, compareToVariable)),
Expression.Label(ret, zero));
return block;
及其调试视图:
.Block(System.Int32 $compareItem1) {
$compareItem1 = .Call ($x.Item1).CompareTo($y.Item1);
.If ($compareItem1 != 0) {
.Return #Label1 { $compareItem1 }
} .Else {
.Default(System.Void)
};
.Label
0
.LabelTarget #Label1:
}
现在我需要用另一种方法中的一些自定义逻辑替换 .Default(System.Void)
。最简单的方法是什么?
Expression
是不可变的,就像 string
一样。要修改它们,您可以使用所需的更改创建它们的副本。通常你使用 ExpressionVisitor 的子类来完成它,比如:
public class DefaultVoidExpressionReplacer : ExpressionVisitor
{
public Expression To;
protected override Expression VisitDefault(DefaultExpression node)
{
if (node.Type == typeof(void))
{
return this.Visit(To);
}
else
{
return base.VisitDefault(node);
}
}
}
你可以像这样使用它:
var newExpression = new DefaultVoidExpressionReplacer
{ To = replaceExpression }.Visit(yourExpression);
您甚至可以决定在 "higher" 级别上工作:Expression.IfThen
级别:
protected override Expression VisitConditional(ConditionalExpression node)
{
DefaultExpression de = node.IfFalse as DefaultExpression;
if (de != null && de.Type == typeof(void))
{
return base.Visit(Expression.IfThenElse(node.Test, node.IfTrue, To));
}
return base.VisitConditional(node);
}
因为 BlockExpression
不允许你就地改变它(它的 Expressions
属性 是类型 ReadOnlyCollection<Expression>
,防止可能的修改)你需要建立一个旧块的新块。
表达式访问者提供了一种简单的编码方式:
class DefaultReplacer : ExpressionVisitor {
protected override Expression VisitGoto(GotoExpression g) {
if (g.Kind != GotoExpressionKind.Return || g.Value == null) {
return base.VisitGoto(g);
}
// If we are here, it's a return expression with Value.
// Check if Value represents default(System.Void),
// and return a replacement expression here
return ...
}
}
按如下方式使用此访客:
Expression modifiedBlock = block.Visit(new DefaultReplacer());