6

特定のセレクターで最小アイテムを見つける拡張メソッドに取り組んでいます。コードの下

    public static T MinBy<T, K>(this IEnumerable<T> src, Func<T, K> selector) where K : struct, IComparable, IConvertible
    {
        var min = default(K);
        T minItem = default(T);
        foreach (var item in src)
        {
            var current = selector(item);
            if (current < min)
            {
                min = current;
                minItem = item;
            }
        }

        return minItem;

    }

エラーが発生しますError Operator '<' cannot be applied to operands of type 'K' and 'K'。しかし、一般的な制約 K を指定しましたStruct and IComparable。これですべての数値データ型が満足できると思います。

では、なぜこれは無効な操作なのですか?

4

2 に答える 2

19

IComparable演算子については何も言いません (そしてできません)。以下を使用する必要があります。

if (current.CompareTo(min) < 0)

演算子は静的であり、overriddenではなくオーバーロードされるだけです。インターフェイス内で演算子を要求することはできません。また、メソッドが存在しても、演算子の動作が魔法のように変わることはありません。(たとえば、オーバーライドしても の動作は変わりません。)Equals==

また、制約は非ジェネリック インターフェイスについてのみIComparable説明するため、すべての操作でボックス化することになることにも注意してください。代わりに制約を変更することをお勧めしますIComparable<K>。(または、制約を削除して、Comparer<K>.DefaultMarが提案したように使用してください。)

メソッドに関するその他のコメント:

  • すべてのキー値がデフォルト値より大きい場合K(例: K=int で、すべてのキーが正)、アイテムは見つかりません。
  • 特定のものを受け入れるオーバーロードが必要なIComparare<K>場合があります (ただし、同等の制約を削除した場合のみ)。
  • K値型に制約する必要はありません。辞書順で最も古い名前の人を見つけたい場合はどうすればよいですか?
  • 要素がない場合は、のデフォルト値を返しますT。LINQ の残りの部分に適合するように、スローすることをお勧めしますInvalidOperationException
  • TSource型パラメーターとしてandを使用しTKeyて、LINQ との一貫性を高めることをお勧めします。

代わりに、 MoreLINQ MinBy 実装を確認することもできます。(もう一度見てみると、null でないことを要求するのが良い考えかどうかはわかりませんcomparer。比較子が null の場合、通常の LINQ と同じようにデフォルトの比較子を使用する必要があります。)

于 2011-02-24T06:57:31.237 に答える
11

IComparableはオペレータサポートを提供しません- を使用する必要がありますcurrent.CompareTo(min)。または、使用するとComparer<T>.Default.Compare(current,min)、制約削除でき、 null などを自動的に処理し、ボクシングを回避できます。

var comparer = Comparer<T>.Default;
...
// loop
    if(comparer.Compare(current, min) < 0) {...}
于 2011-02-24T06:57:49.617 に答える