动态表达式:编译器如何编译以及期望的 lambda 表达式
Dynamic expression: How compiler compiles and what lamda expression to expect
我正在关注这个问题Returning a nested generic Expression<Func<T, bool>>
我对编译器如何读取并将其编译为
感兴趣
例如
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
PropertyInfo pi = typeof(T).GetProperty(prop);
MemberExpression me = Expression.MakeMemberAccess(pe, pi);
ConstantExpression ce = Expression.Constant(val);
BinaryExpression be = Expression.Equal(me, ce);
return Expression.Lambda<Func<T, bool>>(be, pe);
更新 还需要每个方法的解释
我的问题是编译后我应该期待什么 lamda 表达式?
查看下面代码中的注释。
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
var myType = new MyType();
myType.p = "Some Value";
var compareMethod = DoWork<MyType>("Some Value", "p");
var isEqual = compareMethod(myType);
}
public static Func<T, bool> DoWork<T>(object val, string prop)
{
//The code below will construct an expression like 'p => p.prop == value'
//Creates the parameter part of an expression. So the 'p =>' part of the expression.
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
//Get access to the property info, like the getter and setter.
PropertyInfo pi = typeof(T).GetProperty(prop);
// // Constructs the part of the expression where the member is referenced, so the 'p.prop' part.
MemberExpression me = Expression.MakeMemberAccess(pe, pi);
//Creates the constant part of the expression, the 'value' part.
ConstantExpression ce = Expression.Constant(val);
//creates the comparison part '==' of the expression.
//So this requires the left and right side of 'left == right'
//Which is the property and the constant value.
//So 'p.prop == value'
BinaryExpression be = Expression.Equal(me, ce);
//Puts the 'p => ' and 'p.prop == value' parts of the expression together to form the
//complete lambda
//Compile it to have an executable method according to the same signature, as
//specified with Func<T, bool>, so you put a class in of type T and
//the 'p.prop == value' is evaluated, and the result is returned.
return Expression.Lambda<Func<T, bool>>(be, pe).Compile();
}
}
public class MyType
{
public string p { get; set; }
}
}
也就是说,我认为这是一种仅比较的复杂方式。您想到的用例可能证明它是合理的。您是在使用 LINQ-to-SQL 还是必须使用表达式?在大多数情况下,根据我的经验,您可以使用 Funcs 和接口来解决这个问题,如果是第 3 方 classes,则可能与包装器 class 结合使用。代码本身可能会在内存中创建一些 MSIL,然后使用 CLR 的即时编译器在内存中将其编译为本机代码,其中内存的分配被标记为可执行。我没有详细了解它是如何工作的,这只是一个猜测。有关如何为不同目的标记内存分配的更多信息,请参阅 Memory Protection Constants。
我正在关注这个问题Returning a nested generic Expression<Func<T, bool>> 我对编译器如何读取并将其编译为
感兴趣例如
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
PropertyInfo pi = typeof(T).GetProperty(prop);
MemberExpression me = Expression.MakeMemberAccess(pe, pi);
ConstantExpression ce = Expression.Constant(val);
BinaryExpression be = Expression.Equal(me, ce);
return Expression.Lambda<Func<T, bool>>(be, pe);
更新 还需要每个方法的解释
我的问题是编译后我应该期待什么 lamda 表达式?
查看下面代码中的注释。
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace ConsoleApp5
{
class Program
{
static void Main(string[] args)
{
var myType = new MyType();
myType.p = "Some Value";
var compareMethod = DoWork<MyType>("Some Value", "p");
var isEqual = compareMethod(myType);
}
public static Func<T, bool> DoWork<T>(object val, string prop)
{
//The code below will construct an expression like 'p => p.prop == value'
//Creates the parameter part of an expression. So the 'p =>' part of the expression.
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
//Get access to the property info, like the getter and setter.
PropertyInfo pi = typeof(T).GetProperty(prop);
// // Constructs the part of the expression where the member is referenced, so the 'p.prop' part.
MemberExpression me = Expression.MakeMemberAccess(pe, pi);
//Creates the constant part of the expression, the 'value' part.
ConstantExpression ce = Expression.Constant(val);
//creates the comparison part '==' of the expression.
//So this requires the left and right side of 'left == right'
//Which is the property and the constant value.
//So 'p.prop == value'
BinaryExpression be = Expression.Equal(me, ce);
//Puts the 'p => ' and 'p.prop == value' parts of the expression together to form the
//complete lambda
//Compile it to have an executable method according to the same signature, as
//specified with Func<T, bool>, so you put a class in of type T and
//the 'p.prop == value' is evaluated, and the result is returned.
return Expression.Lambda<Func<T, bool>>(be, pe).Compile();
}
}
public class MyType
{
public string p { get; set; }
}
}
也就是说,我认为这是一种仅比较的复杂方式。您想到的用例可能证明它是合理的。您是在使用 LINQ-to-SQL 还是必须使用表达式?在大多数情况下,根据我的经验,您可以使用 Funcs 和接口来解决这个问题,如果是第 3 方 classes,则可能与包装器 class 结合使用。代码本身可能会在内存中创建一些 MSIL,然后使用 CLR 的即时编译器在内存中将其编译为本机代码,其中内存的分配被标记为可执行。我没有详细了解它是如何工作的,这只是一个猜测。有关如何为不同目的标记内存分配的更多信息,请参阅 Memory Protection Constants。