[英]How to change Parameters Expression to Constant Expression in Binary Expression
我有自定義的Visitor,它左右左右移動並將參數更改為常量。
我知道僅更改節點是不可能的。
我應該返回新的lambda表達式,其中包含常量而不是參數。 但是我自己不能創建一個表達式:(
我有以下代碼:
public class ParametersTransformToConstantVisitor : ExpressionVisitor
{
private Dictionary<string, ConstantExpression> parameters = new Dictionary<string, ConstantExpression>();
public ParametersTransformToConstantVisitor(Dictionary<string, ConstantExpression> parameters)
{
this.parameters = parameters;
}
protected override Expression VisitBinary(BinaryExpression node)
{
var constExprLeftName = new Lazy<string>(() => ((ParameterExpression) node.Left)?.Name);
var constExprRightName = new Lazy<string>(() => ((ParameterExpression) node.Right)?.Name);
var constExprName = new Lazy<string>(() => ((ParameterExpression) node.Reduce())?.Name);
ParameterExpression leftParam = null;
ParameterExpression rightParam = null;
if (node.NodeType == ExpressionType.Parameter && parameters.ContainsKey(constExprName.Value))
{
return parameters[constExprName.Value];
}
if (node.Left.NodeType == ExpressionType.Parameter && parameters.ContainsKey(constExprLeftName.Value))
{
leftParam = (ParameterExpression) node.Left;
}
if (node.Right.NodeType == ExpressionType.Parameter && parameters.ContainsKey(constExprLeftName.Value))
{
rightParam = (ParameterExpression) node.Right;
}
if (leftParam != null || rightParam != null)
{
//return Expression.Lambda();
}
return base.VisitBinary(node);
}
}
請幫我建立lambda表達式
感覺您實際上真正需要的是:
protected override Expression VisitParameter(ParameterExpression node)
=> parameters.TryGetValue(node.Name, out var ce) ? (Expression)ce : node;
protected override Expression VisitLambda<T>(Expression<T> node)
=> Expression.Lambda(Visit(node.Body), node.Parameters); // don't visit the parameters
即,每當訪客看到ParameterExpression
, 如果 parameters
映射中有對應的項目,則使用該值。
VisitLambda
上的覆蓋是因為VisitLambda
仍需要返回相同形狀的lambda,並且默認實現也將訪問(並交換) 聲明中的參數。
訪客的工作是擔心圍繞您的更改重新組裝樹。
但是請注意,如果您嘗試創建無參數的lambda ,則可能還需要重寫根目錄。 或者,您可以只使用.Body
並.Body
參數。
例:
Expression<Func<int, int, string>> add = (x, y) => ((2 * x) + y).ToString();
Console.WriteLine(add);
var args = new Dictionary<string, ConstantExpression>
{
["x"] = Expression.Constant(4),
["y"] = Expression.Constant(1),
};
var visitor = new ParametersTransformToConstantVisitor(args);
var result = (LambdaExpression)visitor.Visit(add);
Console.WriteLine(result);
這使:
(x, y) => ((2 * x) + y).ToString()
(x, y) => ((2 * 4) + 1).ToString()
您可以通過以下方式將其設置為無參數lambda:
var withoutArgs = Expression.Lambda<Func<string>>(result.Body);
Console.WriteLine(withoutArgs);
這使:
() => ((2 * 4) + 1).ToString()
次要補充:您可能還想簡化訪問者:
protected override Expression VisitBinary(BinaryExpression node)
{
var visited = base.VisitBinary(node);
if(visited is BinaryExpression be
&& be.Method == null && be.Conversion == null
&& !be.IsLifted
&& be.Left is ConstantExpression left
&& be.Right is ConstantExpression right)
{
object val;
switch(be.NodeType)
{
case ExpressionType.Add:
val = (dynamic)left.Value + (dynamic)right.Value;
break;
case ExpressionType.Multiply:
val = (dynamic)left.Value * (dynamic)right.Value;
break;
case ExpressionType.Subtract:
val = (dynamic)left.Value - (dynamic)right.Value;
break;
case ExpressionType.Divide:
val = (dynamic)left.Value / (dynamic)right.Value;
break;
default:
return visited; // unknown
}
return Expression.Constant(
Convert.ChangeType(val, visited.Type), visited.Type);
}
return visited;
}
這會將輸出更改為:
(x, y) => ((2 * x) + y).ToString()
(x, y) => 9.ToString()
() => 9.ToString()
我們甚至還可以提升ToString()
!
protected override Expression VisitMethodCall(MethodCallExpression node)
{
var visited = base.VisitMethodCall(node);
if (visited is MethodCallExpression mce)
{
if ((mce.Object == null || mce.Object is ConstantExpression)
&& mce.Arguments.All(x => x is ConstantExpression))
{
var obj = (mce.Object as ConstantExpression)?.Value;
var args = mce.Arguments.Select(x => ((ConstantExpression)x).Value).ToArray();
var result = mce.Method.Invoke(obj, args);
return Expression.Constant(result, mce.Type);
}
}
return visited;
}
現在可以給我們:
(x, y) => ((2 * x) + y).ToString()
(x, y) => "9"
() => "9"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.