C# 如何为集合创建与null条件运算符类似的空条件运算符?
C#6.0引入了空条件运算符,这是一个巨大的胜利 现在我希望有一个与之行为类似的操作符,但用于空集合C# 如何为集合创建与null条件运算符类似的空条件运算符?,c#,collections,ienumerable,c#-6.0,null-conditional-operator,C#,Collections,Ienumerable,C# 6.0,Null Conditional Operator,C#6.0引入了空条件运算符,这是一个巨大的胜利 现在我希望有一个与之行为类似的操作符,但用于空集合 Region smallestFittingFreeRegion = FreeRegions .Where(region => region.Rect.W >= width && region.Rect.H >= height) .MinBy(region => (region
Region smallestFittingFreeRegion = FreeRegions
.Where(region => region.Rect.W >= width && region.Rect.H >= height)
.MinBy(region => (region.Rect.W - width) * (region.Rect.H - height));
现在,如果返回一个空的IEnumerable
,则会出现此问题,因为MinBy
(fromMoreLinq
)在集合为空时抛出异常
在C#6.0之前,这可能通过添加另一个扩展方法MinByOrDefault
来解决
我想这样重新编写:.Where(…)?.MinBy(…)
。但这不起作用,因为.Where
返回一个空集合,而不是null
现在可以通过为IEnumerable
引入.NullIfEmpty()
扩展方法来解决这个问题。到达。其中(…).NullIfEmpty()?.MinBy()
最终这看起来很尴尬,因为返回空集合总是比返回null
更好
还有其他更优雅的方法吗?我认为,“最优雅”的解决方案是重新写入到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;
}
}
public static TSource MinByOrDefault(此IEnumerable源,
Func选择器)
{
返回source.MinByOrDefault(选择器、比较器、默认值);
}
公共静态TSource MinByOrDefault(此IEnumerable源,
Func选择器,IComparer(比较器)
{
如果(source==null)抛出新的ArgumentNullException(“source”);
如果(选择器==null)抛出新的ArgumentNullException(“选择器”);
如果(comparer==null)抛出新的ArgumentNullException(“comparer”);
使用(var sourceIterator=source.GetEnumerator())
{
如果(!sourceIterator.MoveNext())
{
返回默认值(TSource);//这是唯一更改的行。
}
var min=sourceIterator.Current;
var minKey=选择器(最小值);
while(sourceIterator.MoveNext())
{
var candidate=sourceIterator.Current;
var candidateProjected=选择器(候选);
if(comparer.Compare(candidateProjected,minKey)<0)
{
min=候选人;
minKey=候选项目;
}
}
返回最小值;
}
}
我认为不太需要特殊运算符。只要使用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));
当然,如果您想提供自己的默认值,以便在类型的默认值不是您想要的情况下使用,您可以使用接受第二个参数的重载。我假设您不会在if
语句中使用Any
调用“优雅”?您提出了两个简单的解决方案,它们紧凑且易于理解。你想要多优雅?你试过这个吗.DefaultIfEmpty().MinBy(region=>(region?.Rect?.W-width)*(region?.Rect?.H-height))
D Stanley,stackoverflow用户的聪明才智经常让我惊讶。空枚举是完全有效的枚举,不需要任何特殊处理,与null不同,null的含义不明确,不允许任何有效操作。您的问题实际上是MinBy
方法对非空输入的要求。此外,如果没有匹配的元素,您希望MinBy
返回什么?如果region是引用类型,这将不起作用,因为这将导致.MinBy.@jbeur中出现空指针异常。正如我所说的,您可以传递任何您想要使用的默认值,如果您想要这样做的话。