Func的逻辑反演<t,bool =“”> </t,>

时间:2014-06-19 21:10:44

标签: c# linq expression-trees func linq-expressions

我的代码库中有一些相当复杂的实体框架查询,我决定将逻辑集中到模型中。基本上,描绘了一堆控制器,它们在表达式树中有大量查询和大量重复代码。因此,我取出了部分表达树并将它们移动到模型中,从而减少了重复次数。

例如,假设我经常需要获取名为Entity的模型,这些模型处于Not Deleted状态。在我的实体模型上,我有:

public static Func<Entity, bool> IsNotDeleted = e =>
    e.Versions != null ?
        e.Versions.OrderByDescending(v => v.VersionDate).FirstOrDefault() != null ?
            e.Versions.OrderByDescending(v => v.VersionDate).First().ActivityType != VersionActivityType.Delete :
            false :
       false;

(这是一个较小的例子,主要是在尝试检查数据之前检查有效数据。)

使用它看起来像:

var entities = EntityRepository.Entities.Where(Entity.IsNotDeleted).Where(...

然而,我发现虽然有时候我想要的是没有删除的记录,但有时我想要删除 的记录。要做到这一点,有没有办法从消费代码中反转逻辑?概念上类似于此的东西(显然不起作用):

var entities = EntityRepository.Entities.Where(!Entity.IsDeleted).Where(...

我不希望在对象上有两个Func<>,一个用于IsDeleted,一个用于IsNotDeleted几乎相同。 Func<>返回bool,是否有一种语法可以在将其放入.Where()子句时调用它的反转?

2 个答案:

答案 0 :(得分:12)

考虑以下扩展方法。

public static class Functional
{
    public static Func<T, bool> Not<T>(this Func<T, bool> f)
    {
        return x => !f(x);
    }

    public static Expression<Func<T, bool>> Not<T>(
        this Expression<Func<T, bool>> f)
    {
        // 1. Break the lambda f apart into its parameters and body.
        // 2. Wrap the body expression with a unary not expression (!).
        // 3. Construct a new lambda with the modified body.
        return Expression.Lambda<Func<T, bool>>(
            Expression.Not(f.Body), f.Parameters);
    }
}

Entity.IsDeleted.Not()Entity.IsNotDeleted()相同。

请注意,您可能希望使用Expression<Func<T, bool>> - 而不是Func<T, bool> - 这样您的lambda逻辑可以用于数据库端而不是客户端。

你可以像这样使用它:

Expression<Func<int, bool>> isNegative = x => x < 0;
Expression<Func<int, bool>> isNonNegative = isNegative.Not();

答案 1 :(得分:1)

您不需要完全功能性的lambda decalration。去Church-Turing方式 - Is Not Deleted定义的递归:

public static Func<Entity, bool> IsNotDeleted = e => !IsDeleted(e);

上面的回答更像是“Church-Turing-y”:)