2

C# 6.0 では、null 条件演算子が導入されました。これは大きなメリットです。

今、私はそれと同様に動作する演算子を持ちたいと思っていますが、空のコレクション用です。

Region smallestFittingFreeRegion = FreeRegions
            .Where(region => region.Rect.W >= width && region.Rect.H >= height)                
            .MinBy(region => (region.Rect.W - width) * (region.Rect.H - height));

コレクションが空の場合、 (from ) は例外をスローするためWhere、空の を返す場合、これは爆発します。IEnumerableMinByMoreLinq

C# 6.0 より前では、これはおそらく別の拡張メソッド MinByOrDefaultを追加することで解決されていました。

次のように書き直します.Where(...)?.MinBy(...)。しかし、 ではなく空のコレクション.Whereを返すため、これは機能しません。null

.NullIfEmpty()これは、 の拡張メソッドを導入することで解決できますIEnumerable。に到着.Where(...).NullIfEmpty()?.MinBy()

空のコレクションを返すことは、null.

これを行うための他のよりエレガントな方法はありますか?

4

2 に答える 2

3

私見、「最もエレガントな」解決策は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;
    }
}

特別なオペレーターの必要性はあまりありません。

于 2016-01-16T03:53:26.197 に答える
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));

もちろん、型の既定値が必要な値でない場合に使用する独自の既定値を提供する場合は、2 番目のパラメーターを受け入れるオーバーロードを使用できます。

于 2016-01-16T03:59:40.690 に答える