问题
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)))
回答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;}
}
回答2:
If you are OK taking a dependency on an implementation detail of Microsoft's .NET Framework/the CoreFX that will break at some time in the future, take a look at what's in the spoiler box below:
There's the Expression.DebugView property. You'll need to do something like finding it via reflection.
It's implemented using an ExpressionVisitor, like what's done in Marc Gravell's answer to this question.
I'm going to emphasize this again: this is a private property.
来源:https://stackoverflow.com/questions/12734464/force-expression-to-evaluate-local-variables