C# ';注入';从一个表达式转换成另一个表达式
我有一个表达式的定义如下:C# ';注入';从一个表达式转换成另一个表达式,c#,linq,expression,C#,Linq,Expression,我有一个表达式的定义如下: Expression<Func<T1, T2, bool>> firstExpression; 如何使用System.Linq.Expressions?您可以通过将参数表达式与常量表达式交换来实现这一点。应该是这样的 实现自定义交换表达式Visitor public class SwapVisitor : ExpressionVisitor { public Expression From { get; set; } publ
Expression<Func<T1, T2, bool>> firstExpression;
如何使用
System.Linq.Expressions
?您可以通过将参数表达式与常量表达式交换来实现这一点。应该是这样的
public class SwapVisitor : ExpressionVisitor
{
public Expression From { get; set; }
public Expression To { get; set; }
public override Expression Visit(Expression node)
{
return node == From ? To : base.Visit(node);
}
}
var swapper = new SwapVisitor
{
From = fistExpression.Parameters[1],
To = Expression.Constant(val)
};
var result = Expression.Lambda<Func<T, bool>>(
swapper.Visit(fistExpression.Body),
fistExpression.Parameters[0]);
var swapper=新SwapVisitor
{
From=fistExpression.参数[1],
To=表达式常数(val)
};
var result=Expression.Lambda(
交换者访问(fistExpression.Body),
fistExpression.参数[0]);
考虑以下示例(firstLambda和secondExpression仅用于查看编译器如何构建表达式)
使用系统;
使用System.Linq.Expressions;
静态void Main(字符串[]参数)
{
表达式firstExpression=(a,b)=>a==b.ToString();
Func firstLambda=(a,b)=>a==b.ToString();
Expression secondExpression=s=>firstLambda(s,45);//这个表达式我只需要看看它是如何编译的
var inputParameter=Expression.Parameter(typeof(string),“s”);
var invocation=Expression.Invoke(firstExpression,inputParameter,Expression.Constant(47));
var ourBuildExpression=Expression.Lambda(调用,新参数Expression[]{inputParameter}).Compile();
Console.WriteLine(ourBuildExpression(“45”));
Console.WriteLine(ourBuildExpression(“47”));
Console.ReadKey();
}
我在调试器监视窗口中检查了Expression secondExpression=s=>firstLambda(s,45)的结果代码>它是调用表达式,所以我手动构造了相同的表达式
您可以看到测试调用返回并按预期打印False和True。您可以使用expression visitor实现这一点:
public static class EmitUtils
{
private class ParameterReplacerVisitor : ExpressionVisitor
{
private ParameterExpression _source;
private Expression _target;
public ParameterReplacerVisitor(ParameterExpression source, Expression target)
{
_source = source;
_target = target;
}
public override Expression Visit(Expression node) =>
node == _source
? _target
: base.Visit(node);
}
public static Expression ReplaceParameter(Expression body, ParameterExpression srcParameter, Expression dstParameter) =>
new ParameterReplacerVisitor(srcParameter, dstParameter).Visit(body);
public static Expression<Func<T1, T3>> BuildClosure<T1, T2, T3>(Expression<Func<T1, T2, T3>> src, T2 closureValue)
{
var constExpression = Expression.Constant(closureValue, typeof(T2));
var body = ReplaceParameter(src.Body, src.Parameters[1], constExpression);
return Expression.Lambda<Func<T1, T3>>(body, src.Parameters[0]);
}
}
公共静态类EmitUtils
{
私有类参数replacervisitor:ExpressionVisitor
{
私有参数表达式_源;
私人表达目标;
公共参数置换器(ParameterExpression源、表达式目标)
{
_来源=来源;
_目标=目标;
}
公共覆盖表达式访问(表达式节点)=>
节点==\u源
?_目标
:base.Visit(节点);
}
公共静态表达式ReplaceParameter(表达式体、参数Expression srcParameter、表达式dstParameter)=>
新参数replacervisitor(srcParameter,dstParameter)。访问(body);
公共静态表达式BuildClosure(表达式src,T2 closureValue)
{
var constExpression=表达式常数(closureValue,typeof(T2));
var body=ReplaceParameter(src.body,src.Parameters[1],constExpression);
返回表达式.Lambda(body,src.Parameters[0]);
}
}
以下是示例用法:
[Test]
public void ClosureTest()
{
Expression<Func<int, string, bool>> CheckStringLength = (len, str) => str.Length < len;
var constString = "some string";
var result = EmitUtils.BuildClosure(CheckStringLength, constString);
Assert.That(result.Compile().Invoke(100), Is.True);
}
[测试]
公共无效ClosureTest()
{
表达式CheckStringLength=(len,str)=>str.Length
是的,这是可行的,但有一个问题:Expression.Invoke不适用于大多数查询提供程序。。。
using System;
using System.Linq.Expressions;
static void Main(string[] args)
{
Expression<Func<string, int, bool>> firstExpression = (a, b) => a == b.ToString();
Func<string, int, bool> firstLambda = (a, b) => a == b.ToString();
Expression<Func<string, bool>> secondExpression = s => firstLambda(s, 45); // this expression I need just to see how it is compiled
var inputParameter = Expression.Parameter(typeof(string), "s");
var invocation = Expression.Invoke(firstExpression, inputParameter, Expression.Constant(47));
var ourBuildExpression = Expression.Lambda<Func<string, bool> > (invocation, new ParameterExpression[] { inputParameter }).Compile();
Console.WriteLine(ourBuildExpression("45"));
Console.WriteLine(ourBuildExpression("47"));
Console.ReadKey();
}
public static class EmitUtils
{
private class ParameterReplacerVisitor : ExpressionVisitor
{
private ParameterExpression _source;
private Expression _target;
public ParameterReplacerVisitor(ParameterExpression source, Expression target)
{
_source = source;
_target = target;
}
public override Expression Visit(Expression node) =>
node == _source
? _target
: base.Visit(node);
}
public static Expression ReplaceParameter(Expression body, ParameterExpression srcParameter, Expression dstParameter) =>
new ParameterReplacerVisitor(srcParameter, dstParameter).Visit(body);
public static Expression<Func<T1, T3>> BuildClosure<T1, T2, T3>(Expression<Func<T1, T2, T3>> src, T2 closureValue)
{
var constExpression = Expression.Constant(closureValue, typeof(T2));
var body = ReplaceParameter(src.Body, src.Parameters[1], constExpression);
return Expression.Lambda<Func<T1, T3>>(body, src.Parameters[0]);
}
}
[Test]
public void ClosureTest()
{
Expression<Func<int, string, bool>> CheckStringLength = (len, str) => str.Length < len;
var constString = "some string";
var result = EmitUtils.BuildClosure(CheckStringLength, constString);
Assert.That(result.Compile().Invoke(100), Is.True);
}