IEnumerable<double> results = ... your query ...
double result = results.MinOrDefault();
MinOrDefault()是不存在的。但是如果我们自己实现它,它看起来会像这样:
public static class EnumerableExtensions
{
public static T MinOrDefault<T>(this IEnumerable<T> sequence)
{
if (sequence.Any())
{
return sequence.Min();
}
else
{
return default(T);
}
}
}
public static TSource? MinOrDefault<TSource>(this IEnumerable<TSource?> source, TSource? defaultValue) where TSource : struct
{
return source.Min() ?? defaultValue;
}
public static TSource? MinOrDefault<TSource>(this IEnumerable<TSource?> source) where TSource : struct
{
return source.Min();
}
public static TResult? Min<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult?> selector, TResult? defaultValue) where TResult : struct
{
return source.Min(selector) ?? defaultValue;
}
public static TResult? Min<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult?> selector) where TResult : struct
{
return source.Min(selector);
}
现在让我们先从更一般的情况开始:
public static TSource MinOrDefault<TSource>(this IEnumerable<TSource> source, TSource defaultValue)
{
if(default(TSource) == null) //Nullable type. Min already copes with empty sequences
{
//Note that the jitter generally removes this code completely when `TSource` is not nullable.
var result = source.Min();
return result == null ? defaultValue : result;
}
else
{
//Note that the jitter generally removes this code completely when `TSource` is nullable.
var comparer = Comparer<TSource>.Default;
using(var en = source.GetEnumerator())
if(en.MoveNext())
{
var currentMin = en.Current;
while(en.MoveNext())
{
var current = en.Current;
if(comparer.Compare(current, currentMin) < 0)
currentMin = current;
}
return currentMin;
}
}
return defaultValue;
}
6条答案
按热度按时间cngwdvgl1#
如果itemList不可为空(其中DefaultIfEmpty给出0),并且您希望null作为潜在的输出值,则也可以使用lambda语法:
qij5mzcb2#
liwlm1x93#
你想要的是:
MinOrDefault()
是不存在的。但是如果我们自己实现它,它看起来会像这样:但是,
System.Linq
中的一些功能将产生相同的结果(以稍微不同的方式):如果
results
序列不包含任何元素,DefaultIfEmpty()
将生成一个包含一个元素的序列-default(T)
,您随后可以在该序列上调用Min()
。如果
default(T)
不是您想要的,则可以使用以下命令指定您自己的默认值:现在,这是整齐!
jmp7cifd4#
注意到到
decimal?
的转换。如果没有,你会得到一个空的结果(只是在事后处理-我主要演示如何停止异常)。我还让“非零”使用!=
而不是>
。amrnrhlw5#
正如已经提到的,在少量代码中只做一次的最简洁的方法是:
将
itm.Amount
转换为decimal?
,并获取最接近的Min
,如果我们希望能够检测此空条件的话。但是,如果您希望实际提供
MinOrDefault()
,那么我们当然可以从以下内容开始:现在,无论是否包含选择器,也无论是否指定默认值,您都拥有了一组完整的
MinOrDefault
。从现在开始,您的代码就是:
所以,虽然它不是那么整洁的开始,它是整洁从那时起。
等等!还有更多!
假设您使用EF并希望利用
async
支持。(Note这里我没有使用
await
我们可以直接创建一个Task<TSource>
,它可以在没有它的情况下完成我们需要的工作,从而避免await
带来的隐藏复杂性)。但是等等,还有更多!假设我们有时在
IEnumerable<T>
中使用这个方法。我们的方法是次优的。当然我们可以做得更好!首先,在
int?
、long?
、float?
、double?
和decimal?
上定义的Min
已经做了我们想要做的事情(正如Marc Gravell的答案所使用的)。类似地,如果为任何其他T?
调用,我们也可以从已经定义的Min
中获得我们想要的行为。和易于内联的方法来利用这一事实:现在让我们先从更一般的情况开始:
现在,使用此方法的明显覆盖:
如果我们真的看好性能,我们可以针对某些情况进行优化,就像
Enumerable.Min()
所做的那样:以此类推,对于
long
、float
、double
和decimal
,匹配Enumerable
提供的Min()
集合。这是T4模板有用的地方。最后,我们得到了
MinOrDefault()
的一个实现,它的性能与我们所希望的差不多,适用于各种类型。(同样,只使用DefaultIfEmpty().Min()
),但如果我们发现自己经常使用它,它会非常“整洁”,因此我们有一个可以重用的好库(或者实际上,粘贴到StackOverflow上的答案中...)。neskvpey6#
这种方法将从
itemList
返回单个最小的Amount
值。理论上,这种方法 * 应该 * 避免多次往返数据库。因为我们使用的是可为null的型别,所以不会再造成null指涉例外状况。
通过避免在调用
Min
之前使用执行方法(如Any
),我们应该只访问数据库一次