12

一連の要素に対して操作を実行しているアプリケーションがあり、操作の正確な性質は操作対象の要素のタイプによって異なります。カプセル化の理由から、要素が操作を実装することは適切ではありません。これは、要素型の仮想メソッドにすることはできないため、「標準」ポリモーフィズムは機能しないことを意味します。これに関連する以前の質問を提出したところ、これはビジター パターンとして知られていると知らされました。

if/elseif以前は、オブジェクトの型に基づいたディスパッチャ メソッドを使用してこれを実装し、適切な実装を呼び出していました。dynamicしかし最近、次のようにキーワードを使用して同じことが達成できることに気付きました。

private void ReconcileTips()
{
    foreach (var step in _definition.Steps)
    {
        ReconcileTips((dynamic)step);
    }
}

private void ReconcileTips(IBulkDispenseDefinition bulkDispense)
{
    bulkDispense.TipType = ReconcileTip(bulkDispense.TipType);
}

private void ReconcileTips(ImportScreenDefinition importScreen)
{
    foreach (var usage in importScreen.ReagentUsages)
        usage.TipType = ReconcileTip(usage.TipType);
}

private void ReconcileTips(BuildScreenDefinition buildScreen)
{
    foreach (var function in buildScreen.Functions)
        function.TipType = ReconcileTip(function.TipType);
}

の各要素のビュー モデルを作成するなど、クラス構造と並行して他の操作に同様のパターンを使用できます_definition.Steps。コンパイラは基本的にこれをif/elseif以前に書いたのと同じロジックに変換し、労力を節約できると考えています。それで、いくつか質問があります:

  1. 私が考慮していない動的ディスパッチに関する落とし穴はありますか? これは一連の を実行するのと同じif (x is TypeA) Do((TypeA)x) else...だと思いますが、間違っている可能性があります。

  2. if/elseifこれは実際には長い方法よりもクリーンで理解しやすいですか?

4

2 に答える 2

10

私が考慮していない動的ディスパッチに関する落とし穴はありますか? これは、一連の if (x is TypeA) Do((TypeA)x) else... を実行するのと同じだと思いますが、間違っている可能性があります。

if (x is TypeA)主な落とし穴は、型がビジター パターンで複数のインターフェイスを実装する場合です。コンパイラはおそらく必要なものを選択しますが、 /else if (x is TypeB)ロジックを使用する場合と同じ選択ではない可能性があります。チェックが発生する順序を制御します。

これは実際には、長い if/elseif メソッドよりもクリーンで理解しやすいですか?

個人的にはそう思います。これにより、実行時のタイプによって決定される、非常にクリーンでかなり適切なパフォーマンスのディスパッチが提供され、「そのまま機能します」。シンプルで短く、きれいなコードに勝るものはありません。渡された間違った型から実行時エラーが発生した場合を (潜在的に) 処理するようにしてください。

于 2013-05-01T21:01:04.593 に答える