0

I have a method I am passing in two times, beginning and end. The user can enter either, both, or none. I then query the db using Linq to find all record between those two times. How would I deal with the cases when beginning and or end parameters are null. If neither are null than it is

where beginning <= time && time <= end

Is there a way to write these cases out without having to use an if, if else, else statement?

Aaron
  • 4,380
  • 19
  • 85
  • 141

2 Answers2

1

Check if the input parameter is null OR if the input parameter matches the conditions.

// from and to are user DateTime? inputs
var filtered = myCollection.Where(x =>
    (from == null || x.Date >= from) &&
    (to == null || x.Date < to));

This works in every scenario...

  • If the user enters no dates, all items are returned.
  • If the user enters from, all items after from are returned.
  • If the user enters to, all items before to are returned.
  • If the user enters both from and to, all items between from and to are returned.

Edit

This works thanks to the || operator being short-circuiting. In my answer, if the optional parameters (from or to) are not specified (thus null) then the expression resolves true and the second condition is not even evaluated. However, if they are not null, then the second condition will be checked as well.

Here is a snippet from the C# spec which I stole from this answer :) that explains (probably better than I could) about short-circuiting operators.

The && and || operators are called the conditional logical operators. They are also called the “shortcircuiting” logical operators.

...

The operation x && y corresponds to the operation x & y, except that y is evaluated only if x is true
The operation x || y corresponds to the operation x | y, except that y is evaluated only if x is not true.

...

The operation x || y is evaluated as x ? true : y. In other words, x is first evaluated and converted to type bool. Then, if x is true, the result of the operation is true. Otherwise, y is evaluated and converted to type bool, and this becomes the result of the operation.

Community
  • 1
  • 1
learningcs
  • 1,856
  • 16
  • 25
  • To the uninitiated this looks like it might fail, perhaps you could explain why it works? – DavidG Dec 11 '15 at 00:33
  • @DavidG Sure... This works because `||` and `&&` are short-circuiting in C#. [This answer has a bunch of information from the C# spec, which details how it works](http://stackoverflow.com/a/4820618/3630637). – learningcs Dec 11 '15 at 00:53
  • Put that in your answer, not in a comment! :) – DavidG Dec 11 '15 at 00:55
0

I have made a small demonstration:

The logic expression that will fill your request was:

(!start.HasValue || start < we.Reception) && (we.Reception < end || !end.HasValue)

Meaning:

(If start does not have value TRUE OR (value smaller than ReceptionValue)) AND (ReceptionValue smaller than end value OR (end does not have value be TRUE))

var myTimes = new List<WeddingEvent>()
{
    new WeddingEvent { Id = 1, Reception = DateTime.Now.AddHours(-3) },
    new WeddingEvent { Id = 2, Reception = DateTime.Now.AddHours(-2) },
    new WeddingEvent { Id = 3, Reception = DateTime.Now.AddHours(-1) },
    new WeddingEvent { Id = 4, Reception = DateTime.Now.AddHours(0) },
    new WeddingEvent { Id = 5, Reception = DateTime.Now.AddHours(1) },
    new WeddingEvent { Id = 6, Reception = DateTime.Now.AddHours(2) },
    new WeddingEvent { Id = 7, Reception = DateTime.Now.AddHours(3) },
};

DateTime? start = null; //DateTime.Now.AddHours(0.5);
DateTime? end = DateTime.Now.AddHours(3.5);
var weddingInHalfAnHour = myTimes.Where(we => (!start.HasValue || start < we.Reception) && (we.Reception < end || !end.HasValue));
foreach (var wedding in weddingInHalfAnHour)
{
    Console.WriteLine("Id: {0} ReceptiontTime: {1}", wedding.Id, wedding.Reception);
}
Orel Eraki
  • 11,940
  • 3
  • 28
  • 36