Динамическое выражение: как компилируется компилятор и какое лямда-выражение ожидать

Я следую этому вопросу Возвращение вложенного универсального выражения ‹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 мне следует ожидать после его компиляции?


person user786    schedule 19.04.2018    source источник
comment
При первом беглом взгляде я ожидал этого (или чего-то подобного): p => [val] == p.[Member] (где [val] - значение / поле val в вашем коде, а [Member] - свойство, указанное значением / полем prop в вашем коде)   -  person bassfader    schedule 19.04.2018
comment
@bassfader можешь объяснить методы?   -  person user786    schedule 19.04.2018
comment
Это слишком широко. Вы обязательно должны прочитать некоторые документы о выражениях и о том, как они работают. ТАК не подходящее место для этого.   -  person HimBromBeere    schedule 19.04.2018
comment
@HimBromBeere есть какой-нибудь хороший источник, кроме msdn, где у них просто расплывчатая информация?   -  person user786    schedule 19.04.2018
comment
См. Также: stackoverflow.com/questions/8315819/ stackoverflow.com/questions/24817283/   -  person Alexander Brattsev    schedule 19.04.2018


Ответы (1)


См. Комментарии в приведенном ниже коде.

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 или вам приходится работать с выражениями? В большинстве случаев из моего опыта вы можете решить эту проблему с помощью функций и интерфейсов, возможно, в сочетании с классом-оболочкой в ​​случае сторонних классов. Сам код, вероятно, создает в памяти какой-то MSIL, который затем компилируется в памяти в собственный код с помощью компилятора Just-In-Time CLR, где выделение памяти помечается как исполняемое. У меня нет подробных сведений о том, как это работает, это всего лишь предположение. Для получения дополнительной информации о том, как выделение памяти может быть помечено для различных целей, см. Константы защиты памяти.

person Mike de Klerk    schedule 19.04.2018
comment
В основном я пытаюсь выполнить это решение stackoverflow.com/questions/49788572/ проверьте это Thx - person user786; 19.04.2018
comment
Хорошо, для этого вы хотите, чтобы выражение возвращало FAFAIK, а не скомпилированный метод. Как это будет в конце концов перенесено на SQL. - person Mike de Klerk; 19.04.2018