如何为类似于 null 条件运算符的集合创建空条件运算符
本文关键字:条件运算符 集合 创建 null 类似于 | 更新日期: 2023-09-27 18:30:39
C# 6.0引入了空条件运算符,这是一个巨大的胜利。
现在,我想要一个行为类似于它的运算符,但用于空集合。
Region smallestFittingFreeRegion = FreeRegions
.Where(region => region.Rect.W >= width && region.Rect.H >= height)
.MinBy(region => (region.Rect.W - width) * (region.Rect.H - height));
现在,如果Where
返回一个空IEnumerable
,这就会爆炸,因为如果集合为空,MinBy
(从MoreLinq
)会抛出异常。
在 C# 6.0 之前,这可以通过添加另一个扩展方法 MinByOrDefault
来解决。
我想这样重写:.Where(...)?.MinBy(...)
.但这不起作用,因为.Where
返回一个空集合而不是null
。
现在,这可以通过引入IEnumerable
的.NullIfEmpty()
扩展方法来解决。抵达.Where(...).NullIfEmpty()?.MinBy()
.
最终,这似乎很尴尬,因为返回空集合总是比返回null
更可取。
有没有其他更优雅的方法可以做到这一点?
恕
我直言,"最优雅"的解决方案是重写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;
}
}
我认为不太需要特殊操作员。
只需使用 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));
当然,如果要提供自己的默认值,以便在类型的默认值不是您想要的时使用,则可以使用重载接受第二个参数。