Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expression Tree GetString Result

I am trying to copy the behavior of Entity Framework in creating the query from expression and i found my way using ExpressionVisitor when getting the property of the model by using Attribute

this is what i got so far

    internal class NVisitor : ExpressionVisitor
    {
        private readonly ParameterExpression _parameter;
        private readonly Type _type;

        public NVisitor(Type type)
        {
            _type = type;
            _parameter = Expression.Parameter(type);
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            return _parameter;
        }

        protected override Expression VisitMember(MemberExpression node)
        {

            if (node.Member.MemberType == MemberTypes.Property)
            {
                var memberName = node.Member.Name;

                PropertyInfo otherMember = _type.GetProperty(memberName);

                var ncols = node.Member.GetCustomAttributes(typeof(NColumn), true);

                if (ncols.Any())
                {
                    var ncol = (NColumn)ncols.First();

                    otherMember = _type.GetProperty(ncol.Name);
                }

                var inner = Visit(node.Expression);
                return Expression.Property(inner, otherMember);
            }

            return base.VisitMember(node);
        }
    }

i have an attribute NColumn that indicates the real name of the property from table column so i mark the property of the model by Attribute

    public class BonusTypeX
    {
        [NColumn("BonusTypeName")]
        public string Name { get; set; }
    }

now when im trying to get the expression,

    [TestMethod]
    public void ExpressionTesting2()
    {
        string searchKey = "Xmas";

        Expression<Func<BonusTypeX, bool>> expression = x => x.Name.Contains(searchKey);

        Type t = typeof(tbl_BonusType);

        var body = new NVisitor(t).Visit(expression.Body);

        string a = string.Join(".", body.ToString().Split('.').Skip(1));


        Assert.AreEqual("BonusTypeName.Contains(\"Xmas\")", a);
    }

i got this

BonusTypeName.Contains(value(Payroll.Test.Administration.TestRepositories+<>c__DisplayClass13).searchKey)

what i am expecting to get is

BonusTypeName.Contains("Xmas")

is there any method that gets the expression string? i am using

string a = string.Join(".", body.ToString().Split('.').Skip(1));

which i think it might be wrong.. :)

any help would be appreciated.

like image 399
Vincent Dagpin Avatar asked Oct 21 '14 05:10

Vincent Dagpin


1 Answers

Local variable are captured in a compiler generated class at runtime, this explains the Payroll.Test.Administration.TestRepositories+<>c__DisplayClass13).searchKey part. To get the generated field's value in your expression you must explicitly replace it's value when visiting the expression:

protected override Expression VisitMember(MemberExpression node)
{    
    if (node.Member.MemberType == MemberTypes.Property)
    {
       var memberName = node.Member.Name;
       PropertyInfo otherMember = _type.GetProperty(memberName);
       var ncols = node.Member.GetCustomAttributes(typeof(NColumn), true);
       if (ncols.Any())
       {
          var ncol = (NColumn)ncols.First();
          otherMember = _type.GetProperty(ncol.Name);
       }

       var inner = Visit(node.Expression);
       return Expression.Property(inner, otherMember);
    }
    if (node.Member.MemberType == MemberTypes.Field)
    {
       if (node.Expression is ConstantExpression)
       {
          var owner = ((ConstantExpression)node.Expression).Value;
          var value = Expression.Constant(((FieldInfo)node.Member).GetValue(owner));
          return value;
       }
    }

    return base.VisitMember(node);
}
like image 58
brz Avatar answered Sep 18 '22 13:09

brz