C#6.0引入了空条件运算符,这是一个很大的胜利。
现在我想拥有一个与它类似的运算符,但是对于空集合。
Where
如果IEnumerable
返回空的MinBy
,这会爆发,因为如果集合为空,MoreLinq
(来自MinByOrDefault
)会抛出异常。
在C#6.0之前,可能会通过添加另一个扩展方法 .Where(...)?.MinBy(...)
来解决这个问题。
我想像这样重写:.Where
。但这不起作用,因为null
会返回空集合而不是.NullIfEmpty()
。
现在可以通过为IEnumerable
引入.Where(...).NullIfEmpty()?.MinBy()
扩展方法来解决这个问题。到达null
。
最终这看起来很尴尬,因为返回空集合总是优先于返回{{1}}。
还有其他更优雅的方法吗?
答案 0 :(得分:2)
恕我直言,"最优雅的"解决方案是重新编写MinBy
以使其进入MinByOrDefault
public static TSource MinByOrDefault<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> selector)
{
return source.MinByOrDefault(selector, Comparer<TKey>.Default);
}
public static TSource MinByOrDefault<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> selector, IComparer<TKey> comparer)
{
if (source == null) throw new ArgumentNullException("source");
if (selector == null) throw new ArgumentNullException("selector");
if (comparer == null) throw new ArgumentNullException("comparer");
using (var sourceIterator = source.GetEnumerator())
{
if (!sourceIterator.MoveNext())
{
return default(TSource); //This is the only line changed.
}
var min = sourceIterator.Current;
var minKey = selector(min);
while (sourceIterator.MoveNext())
{
var candidate = sourceIterator.Current;
var candidateProjected = selector(candidate);
if (comparer.Compare(candidateProjected, minKey) < 0)
{
min = candidate;
minKey = candidateProjected;
}
}
return min;
}
}
我认为不需要特殊的操作员。
答案 1 :(得分:2)
如果它是空的,只需使用DefaultIfEmtpy
来定义要放入序列的默认项目:
Region smallestFittingFreeRegion = FreeRegions
.Where(region => region.Rect.W >= width && region.Rect.H >= height)
.DefaultIfEmpty()
.MinBy(region => (region.Rect.W - width) * (region.Rect.H - height));
当然,如果您想提供自己的默认值,以便在类型的默认值不是您想要的情况下使用,您可以使用接受第二个参数的重载。