问题
Suppose I have two nullable integers:
int? a = 10;
int? b = 20;
I want to take the biggest, non-null value, such that if both values are null, the result is null.
I could write something long-winded such as:
int? max;
if (a == null)
{
max = b;
}
else if (b == null)
{
max = a;
}
else
{
max = a > b ? a : b;
}
This feels a little too clunky (and possibly error-prone) for my liking. What's the simplest way to return the greater value, which also accounts for the possibility of null values?
回答1:
This works for any nullable:
Nullable.Compare(a, b) > 0 ? a : b;
回答2:
In one line using the null coalescing operator:
int? c = a > b ? a : b ?? a;
回答3:
These lines show the necessary logic with a small trick:
if (a == null) return b; // handles b== null also
if (b == null) return a;
// now a!=null, b!=null
return Math.Max(a.Value, b.Value);
or in one line using ?:
(exactly the same logic)
return a == null ? b : b == null ? a : Math.Max(a.Value, b.Value);
Edit
While the answer above is interesting for educational purposes it is not the recomended way to solve this problem. The recomended way is to not reinvent the wheel instead find the matching wheel:
As @roman pointed out there exists a Nullable.Compare()
method which makes this much more readable:
return Nullable.Compare(a, b) > 0 ? a : b;
回答4:
This is a good place for the Null coalescing operator ??
.
It returns the first value if the value is not null
, otherwise it returns the second value.
int? c = a > b ? a : b ?? a;
Proof here
Using the fact that the comparison operator will return false
if either value is null
, the expression will give you the desired result:
a | b || a>b | a | b??a | a>b ? a : b??a
--------------------||----------------------------------
> b | NOT NULL || T | a | -- | a
≤ b | NOT NULL || F | -- | b | b
NOT NULL | NULL || F | -- | a | a
NULL | NOT NULL || F | -- | b | b
NULL | NULL || F | -- | NULL | NULL
回答5:
A short version is:
var result = new[] { a, b }.Max();
回答6:
How about this
private int? Greater(int? a, int? b)
{
if(a.HasValue && b.HasValue)
return a > b ? a : b;
if(a.HasValue)
return a;
if(b.HasValue)
return b;
return null;
}
or more concise:
private int? Greater(int? a, int? b)
{
if(a.HasValue && b.HasValue)
return a > b ? a : b;
return a.HasValue ? a : b;
}
回答7:
!b.HasValue || a > b ? a : b
If b
is null (!b.HasValue
) then a
is always going to be the correct answer.
If b
is not null but a
is, then a > b
will be false, and b
will be the correct answer.
Otherwise it's the same a > b ? a : b
that non-nullable integers would have.
回答8:
How about making a method capable of handling as many nullable values as you have:
public static int? GetLargestNonNull(params int?[] values)
{
IEnumerable<int?> nonNullValues = values.Where(v => v.HasValue);
if (nonNullValues.Any())
{
return nonNullValues.Select(v => v.Value).Max();
}
return null;
}
And use like:
int? result = GetLargestNonNull(a, b);
Except this is also capable of handling:
int? result = GetLargestNonNull(a, b, c, d, e, f);
Or you could change the method parameter to accept a List if you are working with values you've received from another source.
回答9:
I would like to add that the one-line solutions here are good. But to demystify the code a little add a brackets around the null coalescing operator
private int? Max(int? a, int? b)
{
return a > b ? a : (b ?? a);
//returns a if bigger else non null prefering b
}
Returns a
if it is bigger, else return b ?? a
- returns non null (or null if both null) prefering b
回答10:
Here is a very intuitive and readable solution. This will work for any number of values as well as any nullable struct such as say, int? or DateTime?
Also, if all values are null then it returns null.
public static T? GetGreatestOrDefault<T>(IEnumerable<T?> values) where T : struct
{
var any = values.Any(a => a.HasValue);
if (!any) return null;
var firstOrDefault = values.Where(v => v.HasValue)
.Select(v => v.Value)
.OrderByDescending(o => o)
.FirstOrDefault();
return firstOrDefault;
}
or you might want to do the following:
public static T? GreatestOrDefault<T>(this IEnumerable<T?> values) where T : struct
{
var any = values.Any(a => a.HasValue);
if (!any) return null;
var firstOrDefault = values.Where(v => v.HasValue).Max();
return firstOrDefault;
}
来源:https://stackoverflow.com/questions/29985069/take-the-greater-of-two-nullable-values