6

I came across this line of code in a book:

var data = db.Query(sql).OrderByDescending(c => c.DatePosted); 

This sort of thing seems like tail-chasing to me ...

Why is the c => c. necessary? Wouldn't the following be understandable (by the compiler, and even more so by humans)?

var data = db.Query(sql).OrderByDescending(DatePosted); 

I'm sure there's all kinds of fancy stuff going on behind the scenes that purportedly needs this weird lambda syntax, but again:

Why? Is it really necessary? Can't the compiler figure out DatePosted is the column by which to sort?

4

4 に答える 4

27

...なぜc => c.必要なのですか?以下は理解できないでしょうか(コンパイラによって、さらには人間によって...

まず、クエリを人間が読み取れるようにしてラムダを省略したい場合は、人間が読み取り可能でラムダを省略した構文を使用してクエリを記述します。

query = from record in records 
        orderby record.DatePosted descending
        select record;

あなたが述べた理由から、私はその構文を好みます。順序付けメカニズムにキー選択機能が必要であるという事実よりも、読みやすく、ビジネスドメインでのクエリのセマンティクスを強調しています。

第二に、c=>c.は必要ありません。メソッドがあるとします:

static DateTime DatePosted(Record record) { return record.DatePosted; }

これで、必要な構文を使用することが完全に合法になりました。

records.OrderByDescending(DatePosted)

DatePostedコンパイラは、それがソート キーを取得してデリゲートを適切に構築するために呼び出す関数であると推測します。(また、タイプを正しく推測し、意図したとおりに動作することに注意してくださいOrderByDescending<Record, DateTime>。)

より一般的には、C# の基本的な設計原則は、特定の非常に明確に定義された状況 (*) を除いて、言語はユーザーの意図を推測しないということです。クエリは文字通り何でも並べることができるため、コードの作成者は、ソート キーが何であるかを明確に示す必要があります。クエリ構文では、コレクションの要素を表す範囲変数が使用できるため、「各レコードに関連付けられた日付による順序付け」を簡単に表現できます。「日付順」と言うだけでは、推測が必要になります。

ラムダ構文の場合、メソッドには順序キーを選択する関数が必要です。必要に応じて、デリゲート型の値、デリゲート型の値に変換可能なラムダ、またはデリゲート型の値に変換可能なメソッド グループを提供することで、必要な関数を提供できます。「裸の」プロパティは関数ではありません。

では、C# 言語は、プロパティが何のプロパティであるかを説明するコンテキストなしでプロパティの名前を指定すると、コンパイラが推測できるように設計されている可能性がありますか? 「ああ、関数とシーケンスを取る OrderBy というメソッドがここにあることがわかりました。関数に指定された名前が関数であることを意図していると推測させてください」確か に、私はそれを行うことができました.コードを書くのそれほど難しくありません.しかし、それはC#言語の設計原則に沿っていないでしょう.いくつかのキーストロークを節約することの利点は、苦労する価値はありません.意図がコードに明確に記述されているという設計原則に違反している。


(*) 暗黙的に型指定されたローカル、メソッドの型推論、暗黙的に型指定された配列、およびオーバーロードの解決と同様に、これらはすべて、開発者が意図したものについて最適な推測を行うコンパイラを伴います。これらの推測を​​行うためのルールは慎重に文書化されており、あいまいさが検出された場合にほとんどが早期に救済されるように設計されています.

于 2013-03-07T04:34:55.937 に答える
5

単独で記述DatePostedするだけで、型、フィールド、プロパティ、またはメソッド グループを参照する場合があります。たまたま正しい型の引数を取るメソッド グループを参照していたらどうなるでしょうか。そうすると、これは間違ったことをするでしょう。

明示的であることは、時には悪いことではありません。構文

c => c.DatePosted

DatePosted具体的には、入力を受け取り、その入力のフィールド/プロパティを返す関数を意味します。これは柔軟です -- 書くことができます

c => DatePosted(c)

また

c => c.DatePosted()

また

c => new DatePosted(c)

何をする必要があるかによって異なります。

于 2013-03-07T03:28:46.647 に答える
4

ここでいくつかの教育を受けた推測がありますが...

主な理由は、「DatePosted」自体には本質的な意味がないためです。メソッド、プロパティ、型など何でもかまいません。のメソッド シグネチャとも一致しませんがFunc<TSource, TKey>、「コンパイラがもっと賢ければ」という意味だと思います。

ただし、次のように、署名に一致するものを渡すことができます。

public class Foo
{
    public int Age {get; set;}
}

public int GetFooAge(Foo f) { return f.Foo; }

var source = <some mess'o Foos>;

source.OrderByDescending(GetFooAge).Dump();
于 2013-03-07T03:29:43.223 に答える
2

重要なポイントは、そのような機能が文脈に混乱をもたらすということだと思います. 「DatePosted」とは何ですか? どこで定義されていますか? コンパイラはメソッド呼び出しを特定の方法で処理するため、特別な種類のメソッド呼び出しを導入するのは難しいでしょう。これが特別なメソッド呼び出しであることをどうやって知るのでしょうか? コンパイラに必要なすべてのコンテキストを提供する方が、より実用的です。そのため、簡潔なラムダ構文が非常に役立ちます。

于 2013-03-07T03:27:35.027 に答える