私は見ていますMvcContribグリッドコンポーネントと私は魅了されていますが、同時に反発しています。グリッド構文:
.Attributes(style => "width:100%")
上記の構文は、生成されたHTMLのstyle属性を次のように設定します。width:100%
。今あなたが注意を払うならば、「スタイル」はどこにも特定されていません、から推論されます名式内のパラメータの意味私はこれを掘り下げる必要があり、「魔法」が起こる場所を見つけました:
Hash(params Func<object, TValue>[] hash)
{
foreach (var func in hash)
{
Add(func.Method.GetParameters()[0].Name, func(null));
}
}
実際、コードは、属性の名前と値のペアの辞書を作成するために、正式なコンパイル時のパラメータ名を使用しています。結果として得られる構文構成は確かに非常に表現力がありますが、同時に非常に危険です。ラムダ式を一般的に使用すると、名前副作用なしで使用されます。私は言う本の中で例を見ますcollection.ForEach(book => Fire.Burn(book))
私は自分のコードを書くことができることを知っているcollection.ForEach(log => Fire.Burn(log))
そしてそれは同じことを意味します。しかし、ここでMvcContrib Gridの構文を使用すると、突然、変数に選択した名前に基づいて積極的に外観を決定し、決定するコードが見つかります。
では、C#3.5 / 4.0コミュニティやラムダ式を愛する人たちとの共通のやり方なのでしょうか。それとも私が心配してはいけない不正なワントリック異端者ですか?
これは相互運用性が良くありません。たとえば、このC# - F#の例を検討してください。
C#:
public class Class1
{
public static void Foo(Func<object, string> f)
{
Console.WriteLine(f.Method.GetParameters()[0].Name);
}
}
F#:
Class1.Foo(fun yadda -> "hello")
結果:
"arg"が表示されます( "yadda"ではありません)。
結果として、ライブラリ設計者は、これらの種類の '不正使用'を回避するか、または.Net言語間で相互運用性を確保したい場合は少なくとも '標準的な'オーバーロード(文字列名を追加パラメータとして使用)を提供する必要があります。
私はそのおかげであまり変わっていないことがわかります名しかし、ラムダは不要;それは匿名型を使用することができ、そしてより柔軟性があります:
.Attributes(new { style = "width:100%", @class="foo", blip=123 });
これは、(たとえば)ASP.NET MVCの大部分で使用されているパターンです。その他の用途(a警告、また注意してくださいAyendeの考え名前が呼び出し側固有ではなく魔法の値である場合)
HtmlAttributes
期待される属性を持つクラス(インテリセンス用)、そして単にそれらを無視するnull
値... - Marc Gravell♦
私の意見を投げ入れたいだけでした(私はMvcContribグリッドコンポーネントの作者です)。
これは間違いなく言語の乱用です - それについて疑いはありません。しかし、私は実際には直感に反するとは考えていません。Attributes(style => "width:100%", @class => "foo")
何が起こっているのかは明らかだと思います(確かに匿名型のアプローチよりも悪くありません)。理解の観点からすると、私はそれがかなり不透明であることに同意します。
興味がある人のために、MvcContribでの使用に関するいくつかの背景情報...
私は個人的な好みとしてこれをグリッドに追加しました - 私は辞書として匿名型を使うのは好きではありません( "object"をとるパラメータはparams Func []をとるものと同じくらい不透明です)そしてDictionaryコレクション初期化子はどちらかと言えば冗長です(私はまた、冗長な流暢なインターフェースのファンではありません。たとえば、Attribute( "style"、 "display:none")を複数回呼び出して連鎖させる必要があります。Attribute( "class"、 "foo")など)
C#の辞書リテラルの構文がそれほど冗長でない場合は、この構文をグリッドコンポーネントに含める必要はありませんでした。
私はまた、MvcContribでこれを使用することは完全にオプションであることを指摘したい - これらは代わりにIDictionaryをとるオーバーロードをラップする拡張メソッドである。あなたがこのような方法を提供するならば、あなたはまた、例えば他の言語との相互運用のために、より「通常の」アプローチをサポートするべきであることが重要であると思います。
また、誰かが「リフレクションオーバーヘッド」について言及しました、そして私はちょうどこのアプローチではあまりオーバーヘッドがないことを指摘したかった - 実行時リフレクションも式のコンパイルも含まれていません。http://blog.bittercoder.com/PermaLink,guid,206e64d1-29ae-4362-874b-83f5b103727f.aspx)
を好む
Attributes.Add(string name, string value);
それはもっと明白で標準的で、ラムダを使っても何も得られません。
html.Attributes.Add("style", "width:100%");
同じくらい上手に読まないstyle = "width:100%"
(実際に生成されたHTML)style => "width:100%"
それは結果のHTMLでどのように見えるかに非常に近いです。 - Jamie Penney
レールランドへようこそ:)
何が起こっているのかを知っている限り、それには何の問題もありません。 (問題があるのはこの種のことがうまく文書化されていないときです)。
Railsフレームワークの全体は、設定に関する規約の考え方に基づいて構築されています。ある意味で物事に名前を付けることは彼らが使っている慣習にあなたをかぎらせ、あなたは無料でたくさんの機能を手に入れる。命名規則に従うことで、あなたはより速く進んでいます。全体が見事に機能します。
私がこのようなトリックを見たもう一つの場所はMoqのメソッド呼び出しアサーションです。あなたはラムダを渡しますが、ラムダは実行されません。メソッド呼び出しが行われたことを確認するために式を使用し、そうでない場合は例外をスローします。
これは恐ろしい複数のレベルで。いいえ、これはRubyのようなものではありません。これはC#と.Netの悪用です。
タプル、匿名型、流暢なインターフェースなど、もっと簡単な方法でこれを行う方法について多くの提案がありました。
それがそれほど悪くなるのは、それ自身の利益のために空想するのがその正しい方法だということです。
あなたがVBからこれを呼び出す必要があるとき何が起こりますか?
.Attributes(Function(style) "width:100%")
その完全に直感的ではない、インテリセンスは、どのようにしてものを渡すのかを理解するのにほとんど役に立ちません。
不必要に非効率的です。
どのようにしてそれを維持するかについての手がかりは誰にもないでしょう。
属性に入る引数のタイプは何ですか?Func<object,string>
?その意図はどのように明らかになっていますか。 「オブジェクトのすべての値を無視してください」と言っているあなたのインテリセンス文書は何ですか。
私はあなたが完全にそれらの反発の感情を持つことを正当化すると思います。
私は「構文の輝き」キャンプにいる、彼らがそれを明確に文書化するならば、そしてそれはこのおかしくおかしく見えます、それに関してほとんど問題はありません!
私はこのような使い方に出会うことはほとんどありませんでした。 「不適切」だと思います:)
これは一般的な使用方法ではありません。一般的な規則と矛盾します。この種の構文には、もちろん長所と短所があります。
短所
長所
ボトムライン - 公のAPI設計では、もっと明確な方法を選んだほうがいいでしょう。
いいえ、それは確かに一般的なやり方ではありません。直感に反するので、コードを見てそれが何をするのか理解するだけの方法はありません。あなたはそれがどのように使われているかを理解するためにそれがどのように使われているかを知る必要があります。
デリゲートの配列を使用して属性を提供するのではなく、連鎖メソッドの方が明確でパフォーマンスが向上します。
.Attribute("style", "width:100%;").Attribute("class", "test")
これはもう少し入力する必要がありますが、明確で直感的です。
.Attribute("style", "width:100%")
私にくれstyle="width:100%"
しかし、すべての人にとってそれは私に与えることができることを知っていますfoooooo
。違いがわかりません。 - Samantha Branham
"恐ろしさ"についてのこのすべての憤慨は、長い間C#の人たちが過度に反応しすぎていることです(そして私は長い間C#プログラマーであり、それでもこの言語の大ファンです)。この構文について恐ろしいことは何もありません。これは単に、構文を表現しようとしているもののように見せるための試みです。構文の「ノイズ」が少ないほど、プログラマは理解しやすくなります。 1行のコードでノイズを減らすのは少しだけ効果がありますが、ますます多くのコードでそれを積み重ねることを可能にし、それは大きな利益であることがわかります。
これは作者がDSLと同じ利点を得ようとする試みです - あなたが言おうとしているものがコードのように見えるようになれば、魔法の場所にたどり着きます。これが相互運用に適しているのか、それとも「複雑さ」のコストを正当化するのに匿名の方法よりも十分に優れているのかを議論することができます。あなたのプロジェクトでは、この種の構文を使うかどうかの正しい選択をするべきです。しかしそれでも...これはプログラマーによる賢い試みであり、結局のところ、私たち全員がやろうとしていること(実現しているかどうかにかかわらず)です。そして、私たち全員がやろうとしているのは、「コンピュータにしたいことをできるだけ近い言語で、コンピュータに伝えたい」ということです。
社内で考えているのと同じ方法で私たちの指示をコンピュータに表現することに近づくことは、ソフトウェアをより保守しやすく、より正確にするための鍵です。
編集:私は「ソフトウェアをより保守しやすく、より正確にするための鍵」と言っていました。私はそれを「鍵」に変えました。
これを使ってフレーズをコインできますか?
magic lambda(n):マジックストリングを置き換える目的でのみ使用されるラムダ関数。
これは式ツリーの利点の1つです - コード自体で追加情報を調べることができます。こうやって.Where(e => e.Name == "Jamie")
同等のSQL Where節に変換できます。私はそれがこれ以上先に行かないことを願っていますが、これは式ツリーの賢い使い方です。もっと複雑なものは置き換えたいと思っているコードよりも難しいと思われるので、私はそれが自己制限的になると思う。
それは面白いアプローチです。式の右辺を定数のみに制限した場合は、次のように実装できます。
Expression<Func<object, string>>
どちらがデリゲートの代わりにあなたが本当に欲しいものであると思います(あなたは両側の名前を得るためにラムダを使っています) 下記の単純な実装を参照してください。
public static IDictionary<string, string> Hash(params Expression<Func<object, string>>[] hash) {
Dictionary<string, string> values = new Dictionary<string,string>();
foreach (var func in hash) {
values[func.Parameters[0].Name] = ((ConstantExpression)func.Body).Value.ToString();
}
return values;
}
これは、スレッドの前半で言及されているクロスランゲージ相互運用の問題にも対処する可能性があります。
このコードは非常に巧妙ですが、解決する可能性がある問題をさらに引き起こす可能性があります。
ご指摘のとおり、パラメーター名(スタイル)とHTML属性との間には不明瞭な依存関係があります。コンパイル時のチェックは行われません。パラメータ名が誤って入力された場合、ページにはおそらくランタイムエラーメッセージは表示されませんが、ロジックのバグを見つけるのははるかに困難です(エラーはありませんが不正確な動作)。
より良い解決策は、コンパイル時にチェックできるデータメンバを持つことです。だからこれの代わりに:
.Attributes(style => "width:100%");
Styleプロパティを持つコードは、コンパイラによってチェックできます。
.Attributes.Style = "width:100%";
あるいは:
.Attributes.Style.Width.Percent = 100;
それはコードの作者にとってより多くの仕事ですが、このアプローチはC#の強い型チェック能力を利用します。それはバグが最初からコードに入り込むのを防ぐのを助けます。
少なくともRuby =のように思えますが、少なくとも私にとっては後の動的な "lookup"のための静的リソースの使用はAPI設計の考慮には適さないので、このAPIではこの巧妙なトリックはオプションであることを願います。
IDictionaryを継承してもしなくてもかまいませんし、値を設定するためにキーを追加する必要がない場合はphp配列のように動作するインデクサを提供することもできます。これはc#だけでなく.netセマンティクスの有効な使い方であり、それでもドキュメントが必要です。
お役に立てれば
私見、それはそれを行うためのクールな方法です。私たちは皆、クラスControllerに名前を付けることでMVCのコントローラになるという事実を気に入っています。そのため、命名が重要な場合があります。
ここでもその意図は明らかです。それを理解するのはとても簡単です.Attribute( book => "something")
になりますbook="something"
そして.Attribute( log => "something")
になりますlog="something"
慣習のように扱えば問題にならないはずです。私はあなたがより少ないコードを書いて意図を明白にするものは何でも良いことだという意見です。
私の意見では、それはラムダの乱用です。
構文の輝きに関しては私が見つけるstyle=>"width:100%"
わかりにくいです。特に=>
の代わりに=
メソッド(func)名が適切に選択されている場合、これはメンテナンスの頭痛を避けるための素晴らしい方法です(すなわち:新しいfuncを追加しますが、それを関数 - パラメータマッピングリストに追加するのを忘れていました)。もちろん、それを大量に文書化する必要があり、そのクラスの関数の文書からパラメータの文書を自動生成する方がいいでしょう。
私はこれが「魔法の弦」以上のものではないと思います。私はこれのためにも匿名型のファンではありません。より良い& Aが必要です。強く型付けされたアプローチ