0

I am following this question Returning a nested generic Expression<Func<T, bool>> And I am interested in how compiler reads and compile it to

for example

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);

Update Also need explanation of each method

My question is what lamda expression should I expect after it compiles?

user786
  • 3,902
  • 4
  • 40
  • 72
  • At a first quick look I'd expect this (or something similar): `p => [val] == p.[Member]` (where `[val]` is the value / field `val` in your code, and `[Member]` is the property specified by the `prop` value / field in your code) – bassfader Apr 19 '18 at 07:52
  • @bassfader can u explain the methods? – user786 Apr 19 '18 at 07:57
  • 3
    That´s by far too broad. You should definitly read some docu about expressions and how they work. SO isn´t the right place for that. – MakePeaceGreatAgain Apr 19 '18 at 08:00
  • @HimBromBeere any good source beside msdn where they just have vague info? – user786 Apr 19 '18 at 08:03
  • See also: https://stackoverflow.com/questions/8315819/expression-lambda-and-query-generation-at-runtime-simplest-where-example https://stackoverflow.com/questions/24817283/reflection-in-entity-framework-c-sharp/43576239#43576239 – Alexander Brattsev Apr 19 '18 at 08:47

1 Answers1

2

See the comments in the code below.

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; }
    }
}

That said, I think it is a complex way of only comparing. The usage case you have in mind may justify it. Are you working with LINQ-to-SQL or so that you have to work with expressions? In most cases from my epxerience, you can solve this with Funcs and interfaces, maybe in combination with a wrapper class in case of 3rd party classes. The code itself probably creates some in memory MSIL, which is then compiled in memory to native code using the Just-In-Time compiler of the CLR, where the allocation of the memory is marked as executable. I do not have detailed knowledge of how that works, this is just a guess. For more information on how memory allocation can be marked for different purposes see Memory Protection Constants.

Mike de Klerk
  • 11,906
  • 8
  • 54
  • 76
  • Basically I am trying to accomplish this solution https://stackoverflow.com/questions/49788572/dynamic-query-for-creating-where-predicate-with-inner-collection check that out Thx – user786 Apr 19 '18 at 09:32
  • Ok, for that you want to have the expression returned FAFAIK, not the compiled method. As it will be transpiled to SQL in the end. – Mike de Klerk Apr 19 '18 at 11:02