力前pression&LT;&GT;以评估本地变量 [英] force Expression<> to evaluate local variables
问题描述
我有这样的事情在LinqPad
无效的主要()
{
变种T1 = DateTimeOffset.Parse(2012年10月1日);
诠释? N1 = 1;
防爆pression&LT; Func键&lt;样品,布尔&GT;&GT; X1 = UD =&GT;
(ud.Date == T1&功放;&安培; ud.Number == N1);
x1.ToString()转储()。
}
类样品
{
公众诠释?数{设置;获得;}
公众的DateTimeOffset日期{设置;获得;}
}
它输出
UD =>((ud.Date ==值(UserQuery +&LT;> C_的 DisplayClass0).t1)AndAlso (ud.Number ==值(UserQuery +&LT;> C 的_DisplayClass0).n1))
也可把这些变量,但有它的输出是这样的任何可能的方式:
UD =>((ud.Date ==解析(2012年10月1号))AndAlso(ud.Number == 转换(1)))
在这里,我们走;输出第一:
UD =&GT; ((ud.Date == 10/01/2012 00:00:00 +00:00)AndAlso(ud.Number == 1))
这永远不会输出解析(...)
,因为你的前pression的不包含的解析:你已经评估,到时候你把它变成一个lambda。
请注意,该处理捕获的变量的一个级别。对于更复杂的(嵌套)捕捉环境中,你必须递归从捕获类取值:
使用系统;
使用System.Linq.Ex pressions;
使用的System.Reflection;
使用System.Runtime.CompilerServices;
静态类节目
{
静态无效的主要()
{
变种T1 = DateTimeOffset.Parse(2012年10月1日);
诠释? N1 = 1;
防爆pression&LT; Func键&lt;样品,布尔&GT;&GT; X1 = UD =&GT;
(ud.Date == T1&功放;&安培; ud.Number == N1);
VAR消毒=(出pression&LT; Func键&lt;样品,布尔&GT;&GT;)
新Literalizer()访问(X1)。
Console.WriteLine(sanitized.ToString());
}
}
类Literalizer:防爆pressionVisitor
{
保护覆盖防爆pression VisitMember(MemberEx pression节点)
{
如果(node.Member.DeclaringType.IsDefined(typeof运算(CompilerGeneratedAttribute),FALSE)
&功放;&安培; node.Ex pression.NodeType ==前pressionType.Constant)
{
对象目标=((ConstantEx pression)node.Ex pression)。价值,价值;
开关(node.Member.MemberType)
{
案例MemberTypes.Property:
值=((的PropertyInfo)node.Member).GetValue(目标,NULL);
打破;
案例MemberTypes.Field:
值=((字段信息)node.Member).GetValue(目标);
打破;
默认:
值=目标= NULL;
打破;
}
如果(目标!= NULL)返回前pression.Constant(价值node.Type);
}
返回base.VisitMember(节点);
}
}
类样品
{
公众诠释?数{设置;获得;}
公众的DateTimeOffset日期{设置;获得;}
}
I have something like this in LinqPad
void Main()
{
var t1 = DateTimeOffset.Parse("10/1/2012");
int? n1 = 1;
Expression<Func<Sample,bool>> x1 = ud =>
(ud.Date == t1 && ud.Number == n1);
x1.ToString().Dump();
}
class Sample
{
public int? Number{set;get;}
public DateTimeOffset Date{set;get;}
}
it outputs
ud => ((ud.Date == value(UserQuery+<>c_DisplayClass0).t1) AndAlso (ud.Number == value(UserQuery+<>c_DisplayClass0).n1))
is there any possible way to keep the variables but have it output something like this:
ud => ((ud.Date == Parse("10/1/2012")) AndAlso (ud.Number == Convert(1)))
Here we go; output first:
ud => ((ud.Date == 10/01/2012 00:00:00 +00:00) AndAlso (ud.Number == 1))
This will never output Parse(...)
, because your expression does not contain a parse: you have already evaluated that by the time you put it into a lambda.
Note also that this handles one level of captured variable. For more complex (nested) capture contexts, you'll have to recursively fetch the values from the capture classes:
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
static class Program
{
static void Main()
{
var t1 = DateTimeOffset.Parse("10/1/2012");
int? n1 = 1;
Expression<Func<Sample, bool>> x1 = ud =>
(ud.Date == t1 && ud.Number == n1);
var sanitized = (Expression<Func<Sample, bool>>)
new Literalizer().Visit(x1);
Console.WriteLine(sanitized.ToString());
}
}
class Literalizer : ExpressionVisitor
{
protected override Expression VisitMember(MemberExpression node)
{
if(node.Member.DeclaringType.IsDefined(typeof(CompilerGeneratedAttribute), false)
&& node.Expression.NodeType == ExpressionType.Constant)
{
object target = ((ConstantExpression)node.Expression).Value, value;
switch (node.Member.MemberType)
{
case MemberTypes.Property:
value = ((PropertyInfo)node.Member).GetValue(target, null);
break;
case MemberTypes.Field:
value = ((FieldInfo)node.Member).GetValue(target);
break;
default:
value = target = null;
break;
}
if (target != null) return Expression.Constant(value, node.Type);
}
return base.VisitMember(node);
}
}
class Sample
{
public int? Number{set;get;}
public DateTimeOffset Date{set;get;}
}
这篇关于力前pression&LT;&GT;以评估本地变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!