23

カスタムの並べ替え比較子を使用した特定の Linq 式には、次の 2 つの形式があります。

形式 1

var query =
    source
    .Select(x => new { x.someProperty, x.otherProperty } )
    .OrderBy(x => x, new myComparer());

形式 2

var query =
    from x in source
    orderby x // comparer expression goes here?
    select new { x.someProperty, x.otherProperty };

質問:
2 番目の形式の order-by 式の構文は何ですか?

質問ではありません:
最初の形式に示されているカスタム比較機能を使用する方法。

ボーナス クレジット:
上記の 2 つの Linq 形式に実際の正式な名前はありますか?

4

4 に答える 4

22

2 番目の形式の order-by 式の構文は何ですか?

存在しません。orderby句のドキュメントから:

カスタム比較子を指定することもできます。ただし、メソッド ベースの構文を使用する場合にのみ使用できます。


最初の形式でカスタム比較子を使用する方法。

あなたはそれを正しく書きました。IComparer<T>あなたが書いたように渡すことができます。


上記の 2 つの Linq 形式に実際の正式な名前はありますか?

形式 1 は「メソッドベースの構文」 (前のリンクから) と呼ばれ、形式 2 は「クエリ式構文」 (こちらから) と呼ばれます。

于 2012-10-05T20:47:34.090 に答える
2

最初の形式で示されているカスタム比較子の使用方法。

その形式でカスタム比較子を使用することはできません。

上記の 2 つの Linq 形式に実際の正式な名前はありますか?

形式 1 はメソッド構文、形式 2 は「クエリ構文」、

于 2012-10-05T20:46:43.403 に答える
2

これは必ずしも元の質問に答えているわけではありませんが、概説したいくつかの可能性をいくらか拡張します。他の人が同様の問題に遭遇した場合に備えて、これを投稿しています。ここに投稿されたソリューションは、他の場合に役立つ可能性があるオプションによる一般的な順序の概要を示しています。この例では、ファイル リストをさまざまなプロパティで並べ替えます。

/// <summary>
/// Used to create custom comparers on the fly
/// </summary>
/// <typeparam name="T"></typeparam>
public class GenericCompare<T> : IComparer<T>
{
    // Function use to perform the compare
    private Func<T, T, int> ComparerFunction { set; get; }

    // Constructor
    public GenericCompare(Func<T, T, int> comparerFunction)
    {
        ComparerFunction = comparerFunction;
    }

    // Execute the compare
    public int Compare(T x, T y)
    {

        if (x == null || y == null) 
        {
            // These 3 are bell and whistles to handle cases where one of the two is null, to sort to top or bottom respectivly
            if (y == null && x == null) { return 0; }
            if (y == null) { return 1; }
            if (x == null) { return -1; }
        }

        try
        {
            // Do the actual compare
            return ComparerFunction(x, y);
        }
        catch (Exception ex)
        {
            // But muffle any errors
            System.Diagnostics.Debug.WriteLine(ex);
        }

        // Oh crud, we shouldn't be here, but just in case we got an exception.
        return 0;
    }
}

実装では…</p>

        GenericCompare<FileInfo> DefaultComparer;

        if (SortOrder == SORT_FOLDER_FILE)
        {
            DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) =>
            {
                return fr1.FullName.ToLower().CompareTo(fr2.FullName.ToLower());
            });
        }
        else if (SortOrder == SORT_SIZE_ASC)
        {
            DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) =>
            {
                return fr1.Length.CompareTo(fr2.Length);
            });
        }
        else if (SortOrder == SORT_SIZE_DESC)
        {
            DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) =>
            {
                return fr2.Length.CompareTo(fr1.Length);
            });
        }
        else
        {
            DefaultComparer = new GenericCompare<FileInfo>((fr1, fr2) =>
            {
                return fr1.Name.ToLower().CompareTo(fr2.Name.ToLower());
            });
        }

        var ordered_results = (new DirectoryInfo(@"C:\Temp"))
                .GetFiles()
                .OrderBy(fi => fi, DefaultComparer);

大きな利点は、注文ごとに新しいクラスを作成する必要がなく、新しいラムダを接続するだけでよいことです。明らかに、これはあらゆる種類の方法で拡張できるため、いつかどこかで誰かに役立つことを願っています.

于 2013-09-01T05:32:44.067 に答える
2

質問:

オーバーロードがないため、クエリ構文ではこれは不可能です。

質問ではありません:

リフレクションを使用してオブジェクトを比較する場合にのみ、匿名型で比較子を使用できます。比較には型付きの実装を使用することをお勧めします。

型付きの実装を作成したくない場合は、次を使用できますTuple

var query =
    source
    .Select(x => new Tuple<string, int>(x.someProperty, x.otherProperty))
    .OrderBy(x => x, new MyComparer());

public class MyComparer : IComparer<Tuple<string, int>>
{
  public int Compare(Tuple<string, int> x, Tuple<string, int> y)
  {
    return x.Item1.CompareTo(y.Item1);
  }
}

ボーナスクレジット:

  • クエリ構文または理解構文
  • メソッドの構文または拡張メソッドの構文
于 2012-10-05T20:52:39.197 に答える