How to handle nulls in LINQ when using Min or Max?

后端 未结 5 1399
暖寄归人
暖寄归人 2020-12-14 05:48

I have the following Linq query:

result.Partials.Where(o => o.IsPositive).Min(o => o.Result)

I get an exception when result.Parti

相关标签:
5条回答
  • 2020-12-14 06:29

    You can use the DefaultIfEmpty method to ensure the collection has at least 1 item:

    result.Partials.Where(o => o.IsPositive).Select(o => o.Result).DefaultIfEmpty().Min();
    
    0 讨论(0)
  • 2020-12-14 06:31

    A short summary of the calculation of a Min

    - No mediation (Exception!)

       var min = result.Partials.Where(o => o.IsPositive).Min(o => o.Result);
    

    This is your case: if there are no matching elements, then the Min call will raise an exception (InvalidOperationException).

    - With DefaultIfEmpty() -- still troublesome

     var min = result.Partials.Where(o => o.IsPositive)
                              .Select(o => o.Result)
                              .DefaultIfEmpty()
                              .Min();
    

    DefaultIfEmpty will create an enumeration over the 0 element, when there are no elements in the list. How do you know that 0 is the Min or if 0 stands for a list with no elements?

    - Nullable values; A better solution

       var min = result.Partials.Where(o => o.IsPositive)
                                .Min(o => (decimal?)o.Result);
    

    Here Min is either null (because that's equal to default(decimal?)) or the actual Min found.

    So a consumer of this result will know that:

    1. When result is null then the list had no elements
    2. When the result is a decimal value then the list had some elements and the Min of those elements is that returned value.

    However, when this doesn't matter, then min.GetValueOrDefault(0) can be called.

    0 讨论(0)
  • 2020-12-14 06:39

    You can't use Min (or Max) if the sequence is empty. If that shouldn't be happening, you have a different issue with how you define result. Otherwise, you should check if the sequence is empty and handle appropriately, eg:

    var query = result.Partials.Where(o => o.IsPositve);
    min = query.Any() ? query.Min(o => o.Result) : 0; // insert a different "default" value of your choice...    
    
    0 讨论(0)
  • 2020-12-14 06:39

    Yet another way to express it in LINQ is to use Aggregate:

    var min = result.Partials
        .Where(o => o.IsPositive)
        .Select(o => o.Result)
        .Aggregate(0, Math.Min); // Or any other value which should be returned for empty list
    
    0 讨论(0)
  • 2020-12-14 06:39

    Since LINQ lacks methods like MinOrDefault() and MaxOrDefault(), you can create them by yourself:

    public static class LinqExtensions
    {
        public static TProp MinOrDefault<TItem, TProp>(this IEnumerable<TItem> This, Func<TItem, TProp> selector)
        {
            if (This.Count() > 0)
            {
                return This.Min(selector);
            }
            else
            {
                return default(TProp);
            }
        }
    }
    

    Therefore, if the collection has values, the Min() is calculated, otherwise you get the property type's default value.

    An example of use:

    public class Model
    {
        public int Result { get; set; }
    }
    
    // ...
    
    public void SomeMethod()
    {
        Console.WriteLine("Hello World");
        var filledList = new List<Model>
        {
            new Model { Result = 10 },
            new Model { Result = 9 },
        };
        var emptyList = new List<Model>();
        var minFromFilledList = filledList.MinOrDefault(o => o.Result)); // 9
        var minFromEmptyList = emptyList.MinOrDefault(o => o.Result)); // 0
    }
    

    NOTE 1: you don't need to check if the This parameter is null: the invoked Count() already checks that, and it throws the same Exception that you would throw.

    NOTE 2: This solution is good only in situations where the Count() method is cheap to call. All .NET collections are fine since they are all very efficient; it could be a problem for particular customized/non-standard collections.

    0 讨论(0)
提交回复
热议问题