akd
akd

Reputation: 6758

Correct way of inverting Expression<Func<T, bool>>

  public static class PredicateBuilder
    {
        public static Expression<Func<TEntity, bool>> Active<TEntity>(DateTime effectiveDate)
            where TEntity : IValidFromTo
        {
            return e => (e.EffectiveFrom == null || e.EffectiveFrom.Value.Date <= effectiveDate.Date) &&
                        (e.EffectiveTo == null || e.EffectiveTo.Value.Date > effectiveDate.Date);
        }

        public static Expression<Func<TEntity, bool>>Inactive<TEntity>(DateTime effectiveDate) where TEntity : IValidFromTo
        {
            var isActive = Active<TEntity>(effectiveDate);
            return Expression.Lambda<Func<TEntity, bool>>(Expression.Not(isActive.Body), isActive.Parameters[0]);
        }
    }

    public interface IValidFromTo
    {
        public DateTime? EffectiveFrom { get; }
        public DateTime? EffectiveTo { get; }
    }

    public class Product: IValidFromTo
    {
        public Product(int id)
        {
            Id = id;
        }

        private int Id { get; set; }
        public DateTime? EffectiveFrom { get; set; }
        public DateTime? EffectiveTo { get; set; }
    }


    static void Main(string[] args)
        {
            var products = new List<Product>()
            {
                new Product(1){ EffectiveFrom =DateTime.Now.Date.AddMonths(-1),EffectiveTo = DateTime.Now.Date.AddDays(-1)},
                new Product(2){ EffectiveFrom = DateTime.Now.Date, EffectiveTo=DateTime.Now.AddDays(1)},
                new Product(3){ EffectiveFrom =DateTime.Now.Date.AddMonths(1), EffectiveTo = null},
            };

    var activeExpression = PredicateBuilder.Active<Product> 
       (DateTime.Now.Date).Compile();
            var activeProducts= products.Where(activeExpression).ToList();

     `var inactiveExpression = PredicateBuilder.Inactive<Product> 
    (DateTime.Now.Date).Compile();
            var inactiveProducts= products.Where(inactiveExpression ).ToList();

            Console.ReadKey();

        }

This code works fine. My question was raised when I use(!) to get inactive products instead of creating Inactive() method.

If you code for inactiveProducts as: var incativeProducts= products.Where(PredicateBuilder.Active<Product>(DateTime.Now.Date).Compile()!).ToList(); compiler does not complain about the (!) but the result is the same as activeProducts. Basically (!) does not do inversion in that context.

Is this expected outcome? Or what would be the correct way of inverting the Active without having a method like above?

Upvotes: 0

Views: 96

Answers (1)

Blindy
Blindy

Reputation: 67380

var incativeProducts = products
    .Where(PredicateBuilder.Active<Product>(DateTime.Now.Date).Compile()!)
    .ToList();

! in that context does not mean "not", it's a C# 8 feature that means that the nullable returned by Compile() is expected by you to not be null. If you want to negate an expression, the unary ! operator sits, like every other unary operator, at the beginning:

var incativeProducts = products
    .Where(w => !PredicateBuilder.Active<Product>(DateTime.Now.Date).Compile()(w))
    .ToList();

Upvotes: 1

Related Questions