2

What's the proper way of dealing with nullable types like 'DateTime?'? When you need to pick a smaller of 2 dates that are nullable and one of them is null, < or > won't do as comparing null to actual date results in false, so for example:

DateTime? function( DateTime? a, DateTime? b ){
    return a < b ? a : b;
}

would return b if either a or b were null.

Do I have to use if-statements or is there a workaround?

Edit: I'd like not-null to be returned if one of the values is null

Edit: I'm sorry if it was confusing that I used a function as an example. It's not that I wanted to avoid using if-statements. But there's a lot of comparisms between nullable DateTimes and I'd like to avoid creating custom comparators that would require an explicti call and such.

Is it possible to override the default DateTime? comparators?

pikausp
  • 1,142
  • 11
  • 31

4 Answers4

4

You could use Nullable.Compare.

static DateTime? GetLowerDateTime(DateTime? a, DateTime? b)
{
    int val = Nullable.Compare(a, b);
    if (val < 0) return a ?? b;
    if (val > 0) return b ?? a;
    return a; //whichever you want to return if they're equal
}
keyboardP
  • 68,824
  • 13
  • 156
  • 205
3
DateTime? function( DateTime? a, DateTime? b ){
    if(!a.HasValue && !b.HasValue)
        throw new ArgumentNullException();
    else if(!a.HasValue)
        return b;
    else if(!b.HasValue)
        return a;

    return a.Value < b.Value ? a : b;
}

Logic:

  1. If both values are null, throw an exception.
  2. If either A or B is null, return the other.
  3. If neither A or B is null, return whichever is less than the other.
Scorpion
  • 784
  • 7
  • 25
  • So there's no workaround and I gotta stick with if-statement? – pikausp Aug 02 '14 at 15:31
  • The if statement is a way of making it explicit what you intend to happen once you have `null` DateTime's in the mix. Since you already know how you want your function to compare a null DateTime to a DateTime with a value, you *could* overload the operator like in [this answer](http://stackoverflow.com/questions/9618500/needs-overload-operator-and-null-check). – Scorpion Aug 02 '14 at 15:36
  • @Scorpion Thank you scorpio, I had no idea you could override comparators outside the class. – pikausp Aug 02 '14 at 15:41
  • Why wouldn't you be able to compare `null` to `null`? They're equal. Comparing them is legal. Your function shouldn't throw. – Lucas Trzesniewski Aug 02 '14 at 15:53
  • @Scorpion I'm a bit stucked on overriding the operator outside the class as everywhere people say it's not possible. – pikausp Aug 02 '14 at 15:57
  • @Lucas: You're perfectly able to compare `null` to `null`, but it's not clear whether the asker expects a `null` result from two `null` inputs. A throw seems a pretty reasonable exit if you're calling a function to pick the earlier date, but not passing it any dates! – Scorpion Aug 02 '14 at 15:57
  • @Scorpion Would you mind pointing me out in the right direction about overriding the operators outside the class? Haven't been able to find it. – pikausp Aug 02 '14 at 16:07
  • @Scorpion It doesn't seem reasonable to me but well... At least make your function return a `DateTime` so that this behavior is to be expected from its signature. – Lucas Trzesniewski Aug 02 '14 at 16:09
  • @pikausp You can't do that. – Lucas Trzesniewski Aug 02 '14 at 16:10
  • @LucasTrzesniewski So I'll have to stick with explicitly calling a function? – pikausp Aug 02 '14 at 16:18
  • It depends. For simple comparisons yes, you'll have to. but if for instance you're trying to sort a list, you can implement your logic in an `IComparator` and then use `yourList.OrderBy(i => i, yourComparatorInstance)`. One *solution* would be to make your own `Nullable` structure, but I'd advise against that. Another approach would be to make an extension method, ie `dateA.IsLessThan(dateB)`. – Lucas Trzesniewski Aug 02 '14 at 16:45
2

You need to figure out what you want to happen in every case that your function gets called, then write the code to do that thing. I'm a bit concerned that you're looking for "workarounds" to "writing if statements", as if somehow if statements are evil and you shouldn't use them? Don't try to be clever or sneaky -- you are presumably writing an application that needs to work and be maintainable, not entering a code-golf contest.

You should, instead, follow the excellent advice in this answer: spec out how your function needs to work, then implement exactly the specification. Be clear and accurate.

Your function has four possible combinations of inputs, and you need to figure out what the return value is for each of those inputs. From your edits, it seems like you want the function to return a non-null value as often as possible, so that makes things easy:

  1. function(a, b): return whichever of a, b is smaller.
  2. function(a, null): must return a
  3. function(null, b): must return b
  4. function(null, null): must return null

So, we write that:

DateTime? function( DateTime? a, DateTime? b )
{
    // Case 1.
    if (a.HasValue && b.HasValue)
    {
        return a < b ? a : b;
    }

    // Case 2
    if (a.HasValue)
    {
      return a;
    }

    // Case 3 & 4
    return b;
}    
Community
  • 1
  • 1
Michael Edenfield
  • 28,070
  • 4
  • 86
  • 117
1

this should work for you:

DateTime? function( DateTime? a, DateTime? b ){
    return a < b ? a : (b ?? a);
}

?? is the null-coalescing operator. checkout the msdn: null-coalescing operator.

Edit: removed redundant code

latonz
  • 1,601
  • 10
  • 21
  • This won't work in the case of two `null` parameters. – Scorpion Aug 02 '14 at 15:41
  • If both parameters are null it will return null. In the question it isn't specified what should be returned if both are null. – latonz Aug 02 '14 at 15:48
  • @Scorpion it actually works in all cases though it's very slightly redundant: the "true" branch of the ternary can't happen if `a` is `null` so `(a ?? b)` will always return `a` – Michael Edenfield Aug 02 '14 at 15:51