Composing invocations with Expression<Func<T,bool>> the same way as Func<T,bool>

*爱你&永不变心* 提交于 2020-01-11 13:01:14

问题


Consider a class that can be used as a member of multiple other classes:

class Customer {
    public string FirstName {get;set;}
    public string LastName {get;set;}
}
// Both "Order" and "Profile" have a "Customer" property
class Order {
    public Customer Customer {get;set;}
}
class Profile {
    public Customer Customer {get;set;}
}

I want to define a method that makes a checker for an object associated with a Customer. If I want an in-memory checker, I do it like this:

static Func<T,bool> Check<T>(Func<T,Customer> conv, string first, string last) {
    return obj => conv(obj).FirstName == first && conv(obj).LastName == last;
}

I can use my checker for in-memory sequences as follows:

var matchingOrders = orders
    .Where(Check<Order>(x => x.Customer, "Foo", "Bar"))
    .ToList();
var matchingProfiles = profiles
    .Where(Check<Profile>(x => x.Customer, "Foo", "Bar"))
    .ToList();

Now I want to do the same thing with Expression<Func<T,bool>>:

static Expression<Func<T,bool>> Check<T>(Expression<Func<T,Customer>> conv, string first, string last)

Unfortunately, the same trick does not work:

return obj => conv(obj).FirstName == first && conv(obj).LastName == last;

and use it like this:

var matchingOrders = dbContext.Orders
    .Where(Check<Order>(x => x.Customer, "Foo", "Bar"))
    .ToList();
var matchingProfiles = dbContext.Profiles
    .Where(Check<Profile>(x => x.Customer, "Foo", "Bar"))
    .ToList();

This triggers an error:

CS0119: Expression denotes a variable', where amethod group' was expected

Can I compose expressions the same way that I compose delegates?


回答1:


Unfortunately, C# does not currently provide a way to compose expressions from Expression<Func<...>> objects. You have to use expression trees, which is quite a bit longer:

static Expression<Func<T,bool>> CheckExpr<T>(Expression<Func<T,Customer>> conv, string first, string last) {
    var arg = Expression.Parameter(typeof(T));
    var get = Expression.Invoke(conv, arg);
    return Expression.Lambda<Func<T,bool>>(
        Expression.MakeBinary(
            ExpressionType.AndAlso
        ,   Expression.MakeBinary(
                ExpressionType.Equal
            ,   Expression.Property(get, nameof(Customer.FirstName))
            ,   Expression.Constant(first)
            )
        ,   Expression.MakeBinary(
                ExpressionType.Equal
            ,   Expression.Property(get, nameof(Customer.LastName))
            ,   Expression.Constant(last)
            )
        )
    ,   arg
    );
}


来源:https://stackoverflow.com/questions/44088586/composing-invocations-with-expressionfunct-bool-the-same-way-as-funct-bool

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!