C# filtering a collection of objects

I'm writing a method which returns a collection of ProductPeriod objects based on the following filters:

DateTime? from
DateTime? to
bool? includeActive
bool? includeInactive

The ProductPeriod object looks like this:

public class ProductPeriod
{
    public int Id { get; set; }
    public string Name
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
    public bool IsActive { get; set; }
}

So the idea is, that the client can select a to date and/or a from date and/or include active periods and/or include inactive periods. This gives quite a lot of scenarios for the filtering which makes for quite a large method, which I started writing (and didn't finish yet):

public IEnumerable<ProductPeriod> GetFilteredProductPeriods(DateTime? from,     DateTime? to, bool? includeActive, bool? includeInactive)
{            
    // 1. from date only
    if(from.HasValue && to == null && includeActive == null && includeInactive == null)
        return _entities.ProductPeriods.Where(x => x.StartDate >= from.Value).ToList();

    // 2. from and to date
    if(from.HasValue && to.HasValue && includeActive == null && includeInactive == null)
        return _entities.ProductPeriods.Where(x => x.StartDate >= from.Value && x.EndDate <= to.Value).ToList();

    // 3. to date only
    if (to.HasValue && from == null && includeActive == null && includeInactive == null)
        return _entities.ProductPeriods.Where(x => x.EndDate <= to.Value).ToList();

    // 4. from date and show active
    if (from.HasValue && (includeActive != null && includeActive.Value) && to == null && includeInactive == null)
        return _entities.ProductPeriods.Where(x => x.StartDate >= from.Value && x.IsActive).ToList();

    // 5. from, to and show active
    if (from != null && to != null && (includeActive != null && includeActive.Value) && includeInactive == null)
        return _entities.ProductPeriods.Where(x => x.StartDate >= from.Value && x.EndDate <= to.Value && x.IsActive).ToList();

    // 6. to date and show active
    if (to.HasValue && (includeActive != null && includeActive.Value) && from == null && includeInactive == null)
        return _entities.ProductPeriods.Where(x => x.EndDate <= to.Value && x.IsActive).ToList();

    // 7. .... and so on, so forth..
}

I'm wondering if there's a better/smarter way to do this, that I'm not aware of? I.e. some kind of generic way? :-)

Thanks in advance.

Jon Skeet
people
quotationmark

Yes, there's definitely a better way. You should use the way that queries can be built up in LINQ:

public IEnumerable<ProductPeriod> GetFilteredProductPeriods
    (DateTime? from, DateTime? to, bool? includeActive, bool? includeInactive)
{
    IQueryable<ProductPeriod> query = _entities.ProductPeriods;
    if (from != null)
    {
        query = query.Where(x => x.StartDate >= from.Value);
    }
    if (to != null)
    {
        query = query.Where(x => x.EndDate >= to.Value);
    }
    if (includeActive == false)
    {
        query = query.Where(x => !x.IsActive);
    }
    if (includeInactive == false)
    {
        query = query.Where(x => x.IsActive);
    }
    return query.ToList();
}

Note that setting includeInactive=false and includeActive=false will give you no results... you might want to change it to a single parameter which is false (only inactive), true (only active), null (all).

people

See more on this question at Stackoverflow