我有一个疑问:
int maxShoeSize = Workers
.Where(x => x.CompanyId == 8)
.Max(x => x.ShoeSize);
如果公司8根本没有工人,maxShoeSize中会有什么?
更新: 我如何改变查询,以获得0,而不是一个异常?
我有一个疑问:
int maxShoeSize = Workers
.Where(x => x.CompanyId == 8)
.Max(x => x.ShoeSize);
如果公司8根本没有工人,maxShoeSize中会有什么?
更新: 我如何改变查询,以获得0,而不是一个异常?
Max会抛出System。序列不包含元素
class Program
{
static void Main(string[] args)
{
List<MyClass> list = new List<MyClass>();
list.Add(new MyClass() { Value = 2 });
IEnumerable<MyClass> iterator = list.Where(x => x.Value == 3); // empty iterator.
int max = iterator.Max(x => x.Value); // throws System.InvalidOperationException
}
}
class MyClass
{
public int Value;
}
int maxShoeSize=Workers.Where(x=>x.CompanyId==8)
.Max(x=>(int?)x.ShoeSize).GetValueOrDefault();
(假设ShoeSize是int类型)
如果Workers是来自实体框架的DbSet或ObjectSet,您的初始查询将抛出InvalidOperationException,但不是抱怨一个空序列,而是抱怨物化值NULL不能转换为int。
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
.Select(x => x.ShoeSize)
.DefaultIfEmpty()
.Max();
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
.Select(x => x.ShoeSize)
.DefaultIfEmpty(0)
.Max();
DefaultIfEmpty中的0是不必要的。
注意:使用DefaultIfEmpty()的查询可能会显著变慢。 在我的情况下,这是一个简单的查询。defaultifempty (DateTime.Now.Date)。
我懒得分析它,但显然EF试图获得所有行,然后取Max()值。
结论:有时处理InvalidOperationException可能是更好的选择。
我知道这是一个老问题,公认的答案是有效的,但这个问题回答了我关于这样一个空集是否会导致异常或默认(int)结果的问题。
然而,公认的答案,虽然它确实有效,但不是理想的解决方案,恕我直言,这里没有给出。因此,我在我自己的答案中提供了它,以使任何正在寻找它的人受益。
OP的原始代码是:
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize);
这是我如何写它来防止异常并提供默认结果:
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize as int?) ?? 0;
这导致Max函数的返回类型为int?,它允许空结果,然后??将null结果替换为0。
编辑 只是从评论中澄清一些事情,实体框架目前不支持as关键字,所以在使用EF时编写它的方式是:
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max<[TypeOfWorkers], int?>(x => x.ShoeSize) ?? 0;
由于[TypeOfWorkers]可能是一个很长的类名,写起来很乏味,所以我添加了一个扩展方法来帮助解决这个问题。
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或任何其他您需要的值类型。使用这个扩展方法非常简单,只需传入选择器函数,并可选地包含一个用于null的值,该值默认为0。所以上面可以写成这样:
int maxShoeSize = Workers.Where(x => x.CompanyId == 8).MaxOrDefault(x => x.ShoeSize);
希望这能帮助到更多的人。
你可以在.Max()中使用三元来处理谓词并设置它的值;
// assumes Workers != null && Workers.Count() > 0
int maxShoeSize = Workers.Max(x => (x.CompanyId == 8) ? x.ShoeSize : 0);
如果可能的话,您需要处理Workers集合为null/空,但这取决于您的实现。
你可以试试这个:
int maxShoeSize = Workers.Where(x=>x.CompanyId == 8).Max(x => x.ShoeSize) ?? 0;
您可以在执行Max()之前检查是否有任何工作人员。
private int FindMaxShoeSize(IList<MyClass> workers) {
var workersInCompany = workers.Where(x => x.CompanyId == 8);
if(!workersInCompany.Any()) { return 0; }
return workersInCompany.Max(x => x.ShoeSize);
}
如果这是Linq到SQL,我不喜欢使用Any(),因为它会导致对SQL服务器的多次查询。
如果ShoeSize不是一个可空字段,那么使用.Max(..) ??0不能工作,但下面的可以:
int maxShoeSize = Workers.Where(x = >x.CompanyId == 8).Max(x => (int?)x.ShoeSize) ?? 0;
它绝对不会改变发出的SQL,但如果序列为空,它会返回0,因为它改变了Max()以返回int?而不是int型。