23

当然、読みやすさの点ではありません。個別のメソッドをいつでも個別の行に配置できるからです。むしろ、何らかの理由で、過度に多数のメソッドを一緒にチェーンすることは危険ですか? 私は主にメソッド チェーンを使用して、個々の使い捨て変数を宣言するスペースを節約し、伝統的に呼び出し元を変更するメソッドの代わりに戻りメソッドを使用しています。文字列メソッドを除いて、私が容赦なく連鎖させているもの。いずれにせよ、非常に長いメソッド チェーンをすべて 1 行で使用した場合の影響について心配することがあります。

誰かのユーザー名に基づいて 1 つのアイテムの値を更新する必要があるとしましょう。残念ながら、正しいユーザーを取得する最短の方法は次のようになります。

SPWeb web = GetWorkflowWeb();
SPList list2 = web.Lists["Wars"];
SPListItem item2 = list2.GetItemById(3);
SPListItem item3 = item2.GetItemFromLookup("Armies", "Allied Army");
SPUser user2 = item2.GetSPUser("Commander");
SPUser user3 = user2.GetAssociate("Spouse");
string username2 = user3.Name;
item1["Contact"] = username2;

2 または 3 を含むものはすべて 1 回の呼び出しでしか持続しないため、次のように要約できます (これにより、余計な 1 を取り除くこともできます)。

SPWeb web = GetWorkflowWeb();
item["Contact"] = web.Lists["Armies"]
                     .GetItemById(3)
                     .GetItemFromLookup("Armies", "Allied Army")
                     .GetSPUser("Commander")
                     .GetAssociate("Spouse")
                     .Name;

確かに、すべてが 1 行に収まっていて、int.Parse(ddlArmy.SelectedValue.CutBefore(";#", false))代わりに3. それにもかかわらず、これはこれらのチェーンの平均的な長さの 1 つです。可読性を除いて、これらの 10 以上のメソッド チェーンについて心配すべきことはありますか? それとも、本当に長いメソッドチェーンを使用しても害はありませんか?

4

5 に答える 5

34

メソッドチェーンの長さに技術的な制限はありません。

ただし、問題になる可能性のある 3 つの領域は、デバッグ例外処理、およびリソースの処理です。

デバッグは、チェーンを非常に洗練されたものにするのと同じ事実によって複雑になります。つまり、中間の一時変数がないということです。残念ながら、一時変数がないと、デバッグ時に中間結果を検査するのが苦痛になります。

例外処理は、あるメソッドから発生した例外と別のメソッドから発生した例外を分離できないという事実によって複雑になります。通常、例外に応答して意味のあることを行うことができない場合、これは問題ではありません。呼び出しチェーンを伝播させてください。ただし、後で例外処理が必要であることに気付いた場合は、チェーン構文をリファクタリングして、適切な try/catch ハンドラーを挿入できるようにする必要があります。

リソースの決定論的処分の場合は、例外処理に似ています。C# でこれを実現する最も簡単な方法は、using()残念ながら、チェーン構文によりそれができなくなります。破棄可能なオブジェクトを返すメソッドを呼び出す場合は、構文の連鎖を避けることをお勧めします。これにより、適切な「コード市民」になり、それらのリソースをできるだけ早く破棄できます。

メソッド チェーン構文は、多くの場合、流暢な APIで使用されます。これにより、コードの構文が、意図する操作のシーケンスをより厳密に反映できるようになります。LINQ は .NET の 1 つの例であり、流暢/連鎖構文がよく見られます。

于 2010-05-17T13:04:45.060 に答える
7

読みやすさは最大の懸念事項ですが、多くの場合、それはまったく問題ではありません。

LINQ クエリ構文を (その下に)まさにそのようなセットアップとして記述することもできます。それはそれをよりきれいに見せるだけです;-p

考えられる問題の 1 つは、usingまたはlock;などを導入する必要がある場所です。流暢な API を使用すると、これらのコンポーネントを単純に削除したくなるかもしれませんが、例外がスローされたときにおかしなことが起こる可能性があります。

考えられるもう 1 つの考えは、いくつかの呼び出しに関して、よりきめ細かい例外処理を行いたいということです。しかし、いつでも流れを壊すことができます:

var foo = bar.MethodA().MethodB(...).MethodC();
try {
    foo.MethodD();
} catch (SomeSpecificException) {
    //something interesting
}

または、流暢な外観を維持するために拡張メソッドでそれを行うこともできます。

bar.MethodA().MethodB(...).MethodC().MyExtensionMethodD();

MyExtensionMethodD、特別な処理 (例外、ロック、使用など) で追加するものです。

于 2010-05-17T13:06:55.780 に答える
6

これはコードの臭いと見なされる人もいれば、そうでない人もいます。次の表示がある場合:

Foo.getBar().getBlah().getItem().getName();

「本当に欲しいものは何だろう?」と考えるべきです。代わりに、おそらくメソッドに関数呼び出しを含める必要があります。

String getName(Int _id, String _item)
{
    return myBar.getName( _id, _item );
}

次に、クラス間で下方にデリゲートします。次に、後の更新でクラスの 1 つで何かが変更された場合、それが発生した場所を正確に確認し、1 つの場所で変更できます。

于 2010-05-17T13:08:42.690 に答える
4

これに関して考慮すべき唯一の懸念事項 (可読性を無視する場合) は、リソース処理と GC です。質問する必要があるのは次のとおりです。

  • 私が行っている呼び出しは、破棄する必要があるオブジェクトを返していますか?
  • GC がより反応する可能性のある小さなスコープではなく、単一のスコープ内で多くのものを開始していますか? (GC は、スコープを離れるたびに実行されるようにスケジュールされていますが、スケジュールと実際に実行されるタイミングは 2 つの異なるものです :-p)。

しかし、実際には.. 1行ごとに1つのメソッドを呼び出すか、それらをすべてつなぎ合わせると、ILですべてが同じになる(またはほぼ同じになる)場合があります。

ジョシュ

于 2010-05-17T13:05:40.413 に答える