与参数C#一起使用时,表达式树会出错。但值得用得好

时间:2017-03-02 09:42:34

标签: c# entity-framework lambda expression-trees

我有通用商业服务(BS)课程。我使用这个BS类从DB获取数据。为了获取我发送给它的数据Expression.This Expression是用DTO对象创建的。 BS使用Custome Visitor Class将其转换为EF对象。 当我发送带有值的表达式时(如下)

Expression<Func<UserDT, bool>> t = x => x.Username == "tebo" && x.Password =="ICy5YqxZB1uWSwcVLSNLcA==" && x.Company.Id == new Guid("D88F5A20-5FBE-47FA-B3C0-B7F1241C0D45");

我得到数据。有用。但是,如果我想获取带参数的数据,我会收到错误

var psw = "ICy5YqxZB1uWSwcVLSNLcA==";
string username = "tebo";
Expression<Func<UserDT, bool>> t = x => x.Username == username && x.Password == psw && x.Company.Id == new Guid("D88F5A20-5FBE-47FA-B3C0-B7F1241C0D45");

错误:

  

运营商的操作数&#39; Equal&#39;不匹配方法的参数&#39; op_Equality&#39;。

如何将参数作为值传递?

谢谢。

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq.Expressions;

namespace CXFServer.Net.Test.UTest.MyTest
{
    /// <summary>
    /// Summary description for StackOverFlow
    /// </summary>
    [TestClass]
    public class StackOverFlow
    {
        [TestMethod]
        public void TestingWithoutParameters()
        {
            Expression<Func<UserDT, bool>> t = x => x.Username == "tebo" && x.Password == "ICy5YqxZB1uWSwcVLSNLcA==" && x.Company.Id == new Guid("D88F5A20-5FBE-47FA-B3C0-B7F1241C0D45");
            var expectedUserDt = new UserBS().Login(t);
            Assert.IsTrue(expectedUserDt);
        }

        [TestMethod]
        public void TestingWithParameters()
        {

            var psw = "ICy5YqxZB1uWSwcVLSNLcA==";
            string username = "tebo";
            Expression<Func<UserDT, bool>> t = x => x.Username == username && x.Password == psw && x.Company.Id == new Guid("D88F5A20-5FBE-47FA-B3C0-B7F1241C0D45");

            var expectedUserDt = new UserBS().Login(t);

            Assert.IsTrue(expectedUserDt);
        }
    }


    class User
    {
        public System.Guid UserId { get; set; }
        public string UserFirstName { get; set; }
        public string UserLastName { get; set; }
        public string UserEmail { get; set; }
        public string UserUsername { get; set; }
        public string UserPassword { get; set; }
        public Nullable<int> UserRole { get; set; }
        public Guid User_CompanyId { get; set; }
        public Nullable<System.DateTime> UserModifyDate { get; set; }
        public Nullable<bool> UserStatus { get; set; }
    }

    class UserDT
    {
        public Guid Id
        {
            get;
            set;
        }
        public bool Status
        {
            get;
            set;
        }

        public DateTime ModifyDate
        {
            get;
            set;
        }

        public string FirstName
        {
            get;
            set;
        }

        public string LastName
        {
            get;
            set;
        }

        public string Email
        {
            get;
            set;
        }

        public string Username
        {
            get;
            set;
        }

        public string Password
        {
            get;
            set;
        }

        public int Role
        {
            get;
            set;
        }

        public CompanyDT Company
        {
            get;
            set;
        }


    }

    class CompanyDT : BaseDT
    {
        public string Name
        {
            get;
            set;
        }
    }

    class BaseDT
    {
        public Guid Id
        {
            get;
            set;
        }
        public bool Status
        {
            get;
            set;
        }

        public DateTime ModifyDate
        {
            get;
            set;
        }
    }

    class BaseBS<UserDT, User>
    {

        public bool FindBy(Expression<Func<UserDT, bool>> predicateDt)
        {
            //parameter that will be used in generated expression
            var param = Expression.Parameter(typeof(User));
            var visitor = new Visitor<UserDT, User>(param);
            var body = visitor.Visit(predicateDt.Body);
            //Expression body = new AToBConverter<T, E>(DataTransformation.DataTransformation.QueryMappings).Visit(predicateDt);
            Expression<Func<User, bool>> predicate = Expression.Lambda<Func<User, bool>>(body, param);
            //Expression<Func<E, bool>> predicate = (Expression<Func<E, bool>>)(body,param);
            //IQueryable<User> query = ContextFactory.Retrieve().Set<User>().Where(predicate);

            return true;
        }
    }

    class Visitor<T, E> : ExpressionVisitor
    {
        ParameterExpression _parameter;

        //there must be only one instance of parameter expression for each parameter 
        //there is one so one passed here
        public Visitor(ParameterExpression parameter)
        {
            _parameter = parameter;
        }

        //this method replaces original parameter with given in constructor
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return _parameter;
        }

        protected override Expression VisitConstant(ConstantExpression node)
        {
            return base.VisitConstant(node);
        }

        //protected override visi

        //this one is required because PersonData does not implement IPerson and it finds
        //property in PersonData with the same name as the one referenced in expression 
        //and declared on IPerson
        protected override Expression VisitMember(MemberExpression node)
        {
            if (node.Type.Name.IndexOf("DT") > -1)
            {
                return Visit(node.Expression);
            }

            if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
            {
                return Visit(node.Expression);

            }
            //throw new NotImplementedException();

            string memberName = string.Empty;
            if (node.Type.Name.IndexOf("DT") > -1)
            {
            }
            else
            {
                if (node.Expression.Type.Name.IndexOf("DT") > 0 && node.Expression.Type.Name.Substring(0, node.Expression.Type.Name.IndexOf("DT")) != typeof(E).Name)
                {
                    string type = node.Expression.Type.Name.Substring(0, node.Expression.Type.Name.IndexOf("DT"));
                    memberName = typeof(E).Name + "_" + type + "Id";
                }
                else
                {
                    memberName = typeof(E).Name + node.Member.Name;
                }
            }

            //name of a member referenced in original expression in your 
            //sample Id in mine Prop
            //var memberName = node.Member.Name;
            //find property on type T (=PersonData) by name
            var otherMember = typeof(E).GetProperty(memberName);
            //visit left side of this expression p.Id this would be p
            var inner = Visit(node.Expression);
            return Expression.Property(inner, otherMember);
        }
    }

    class UserBS : BaseBS<UserDT, User>
    {
        public UserBS()
            : base()
        {
        }

        public bool Login(Expression<Func<UserDT, bool>> predicateDt)
        {
            return  FindBy(predicateDt);

        }
    }
}

1 个答案:

答案 0 :(得分:2)

很难遵循VisitMember的逻辑,但主要问题是以下分支:

if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
{
    return Visit(node.Expression);
}

这意味着,如果您有obj.field,则会转换为obj,这是不正确的。

当你使用常量时,代码永远不会达到那个条件,这就是它工作的原因。但是,当表达式使用捕获的变量(闭包)时,它确实存在,这就是它不起作用的原因。

修复是通过调用基本实现来正确处理大小写:

if (node.Member.MemberType != System.Reflection.MemberTypes.Property)
{
    return base.VisitMember(node);
}