NET问答: 如何避免在EmptyEnumerable上执行Max()抛出的异常?

咨询区

Naor

我有下面的一个查询:

int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                          .Max(x => x.ShoeSize);

如果 Workers.Where(x => x.CompanyId == 8) 没有查到任何 Workers 的话,上面的代码将会抛出异常。.

现在的想法是:查不到的话 query 可以返回 0,但千万不要抛异常,我该如何修改上面的 query 呢?

回答区

Ron K.

可以用 IEnumerable 的扩展方法 DefaultIfEmpty() 来避免这种尴尬,参考如下代码。

    class Program
    {
        static void Main(string[] args)
        {
            List<Worker> Workers = new List<Worker>()
            {
                new Worker(){ CompanyId=1, CompanyName="tweet", ShoeSize=10 },
                new Worker(){ CompanyId=2, CompanyName="google", ShoeSize=20 },
            };

            int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                          .Select(x => x.ShoeSize)
                          .DefaultIfEmpty(0)
                          .Max();

            Debug.WriteLine($"maxShoeSize={maxShoeSize}");
        }

    }

    class Worker
    {
        public int CompanyId { get; set; }

        public string CompanyName { get; set; }

        public int ShoeSize { get; set; }
    }

输出结果:

maxShoeSize=0

当然上面的 0 不是必须的,你可以改成其他的任何数。

CptRobby

楼上那哥们提供的方案虽然可以正常运行,但看起来不是很入眼,可以改造成下面这样。

    int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                             .Select(x => (int?)x.ShoeSize)
                              .Max() ?? 0;

代码看起来是不是有点冗长,最好的方式还是自定义一个 扩展方法,如下代码所示:

public static int MaxOrDefault<T>(this IQueryable<T> source, Expression<Func<T, int?>> selector, int nullValue = 0)
{
    return source.Max(selector) ?? nullValue;
}

为了简单,这个扩展方法仅处理了 int 类型,你可以改成任意类型如:(long,double,...),接下来可以继续改造一下调用方。

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).MaxOrDefault(x => x.ShoeSize);

希望我的答案可以帮助到更多人。

点评区

小编从来不敢在 Empty Collection 上做 Max,毕竟被坑的不是一次两次了,所以每次都提前判断集合是否存在值再执行 Max,没想到还有神奇的扩展方法 DefaultIfEmpty 和 可空类型 可以帮忙搞定,感觉学的都忘了。