取两个可以为空的值

假设我有两个可以为空的整数:

int? a = 10; int? b = 20; 

我想取最大的非null值,这样如果两个值都为null,则结果为null。

我可以写一些啰嗦的东西,例如:

 int? max; if (a == null) { max = b; } else if (b == null) { max = a; } else { max = a > b ? a : b; } 

对于我的喜好,这感觉有点过于笨重(并且可能容易出错)。 返回更大值的最简单方法是什么,这也是空值的可能性?

这适用于任何可以为空的:

 Nullable.Compare(a, b) > 0? a: b; 

在一行中使用null合并运算符:

 int? c = a > b ? a : b ?? a; 

这些行显示了一个小技巧的必要逻辑:

 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); 

或者在一行中使用?:完全相同的逻辑)

  return a == null ? b : b == null ? a : Math.Max(a.Value, b.Value); 

编辑

虽然上述答案对于教育目的而言很有意思,但并不是解决这个问题的推荐方法。 推荐的方法是不重新发明轮子而是找到匹配的轮子:

正如@roman指出的那样,存在一个Nullable.Compare()方法,这使得它更具可读性:

 return Nullable.Compare(a, b) > 0 ? a : b; 

这是Null合并算子的好地方??
如果值不为null ,则返回第一个值,否则返回第二个值。

 int? c = a > b ? a : b ?? a; 

certificate在这里

如果任一值为null ,则使用比较运算符将返回false的事实,表达式将为您提供所需的结果:

 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 

简短版本是:

 var result = new[] { a, b }.Max(); 

这个怎么样

  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; } 

或者更简洁:

  private int? Greater(int? a, int? b) { if(a.HasValue && b.HasValue) return a > b ? a : b; return a.HasValue ? a : b; } 
 !b.HasValue || a > b ? a : b 

如果b为null( !b.HasValue ),则a始终是正确的答案。

如果b不为null但是a ,则a > b将为false, b将是正确答案。

否则它是相同的a > b ? a : b a > b ? a : b不可为空的整数会有。

如何制作一个能够处理尽可能多的可空值的方法:

 public static int? GetLargestNonNull(params int?[] values) { IEnumerable nonNullValues = values.Where(v => v.HasValue); if (nonNullValues.Any()) { return nonNullValues.Select(v => v.Value).Max(); } return null; } 

并使用如下:

 int? result = GetLargestNonNull(a, b); 

除此之外还能够处理:

 int? result = GetLargestNonNull(a, b, c, d, e, f); 

或者,如果您正在使用从其他来源收到的值,则可以更改方法参数以接受列表。

我想补充一点,这里的单线解决方案很好。 但是为了揭开代码的神秘面纱 ,在null合并运算符周围添加一个括号

 private int? Max(int? a, int? b) { return a > b ? a : (b ?? a); //returns a if bigger else non null prefering b } 

如果它更大则返回b ?? a ,否则返回b ?? a b ?? a – 返回非null(如果两者都为null,则返回null)更喜欢b

这是一个非常直观和可读的解决方案。 这适用于任何数量的值以及任何可以为null的结构,例如say,int? 还是日期时间?

此外,如果所有值都为null,则返回null。

  public static T? GetGreatestOrDefault(IEnumerable 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; } 

或者您可能想要执行以下操作:

  public static T? GreatestOrDefault(this IEnumerable 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; }