5

今日、最初の C# イテレータを書きました。うふふ。

興味深いことに、それには副作用があります。私のイテレータはディレクトリから無効なファイルを除外し、処理する有効なファイルのシーケンスを返します。invlaid ファイルを検出すると、それを別のディレクトリに移動します。

LINQ クエリとして実装しようとしましたが、where 句の述語に副作用があるという事実が本当に気に入りません。確かな匂いです。

明示的に実装して、すべてのファイルをループし、良いものと悪いものを順番に処理することもできますが、あまりエレガントではありません。より良い解決策は、それを 2 つのリスト (良いリストと悪いリスト) に分割し、それぞれを順番に処理することです。

しかし、イテレータを思い出しました。これで、有効なファイルを生成し、無効なファイルを処理 (移動) する反復子ができました。

だから、私の質問はこれです: イテレータがこのような副作用を持つのは悪い考えですか? イテレータに隠しすぎていませんか?

4

9 に答える 9

4

副作用のあるイテレータは悪いですか?:)

すべてのファイルを含むシーケンスがある場合、すべてのアイテムを訪問し、ケースごとに関数を呼び出す、ビジターのようなものを持つことができます。訪問者の識別は、提供できる述語として、または訪問者に固有のもののいずれかです。

したがって、私は C# は話せませんが、次の疑似コードのようなものです。

good_handler = new FileHandler() {
  handle(File f) { print "Yay!"; }
}

bad_handler = new FileHandler() {
  handle(File f) { print "Nay!"; }
}

files = YourFileSequence();
visitor = new Visitor(good_handler, bad_handler);
visitor.visit(files);
于 2008-11-26T11:44:58.880 に答える
3

イテレータに副作用を持たせるのは一般的に悪い考えだと思いますが、完全にダメというわけではありません。副作用がある場合、呼び出し元が純粋に機能的な方法で作業することが難しく/不可能になります。ユースケースによっては、これが問題になる場合とそうでない場合があります。

イテレータを取得するには2つの方法があることをお勧めします.1つは副作用があります(これはおそらく最適化です)。これは、メソッドにフラグを渡すか、2 つのメソッドに異なる名前を付けることで実現できます。

于 2008-11-26T11:39:31.107 に答える
1

コレクションに対する論理的な列挙である反復子には、副作用があってはなりません。特に、IEnumerator.Reset() メソッドで再起動すると、べき等になりません。

ただし、イテレータは事実上一種のコルーチンであるため、非同期ワークフローのステップなど、他の方法では実装しにくいものを実装するのに役立ちます。

于 2008-11-26T11:44:58.320 に答える
1

もう 1 つの懸念事項は、返される結果に実際に関心を持たずに、呼び出し元がファイルを移動するためにメソッドを使用しようとする可能性があるという意味で、メソッドが「誤用」される可能性があることです。

呼び出し元が結果を反復処理しない場合、(意図した) 副作用は反復子の遅延実行によって呼び出されません。ユーザーがコレクションの一部のみを反復処理するシナリオもあるため、すべてではなく一部のアイテムに対して副作用が実行されます。

この問題については、次の投稿で説明しています: http://codequota.com/archive/2012/02/13/iterator-blocks-and-side-effects.aspx

于 2012-02-14T02:36:52.150 に答える
0

私の経験則では、コレクションを反復処理している場合はノーです。しかし、Python では、コードを特定の回数だけ実行するために for ループが慣用的に使用されることがよくあります。

于 2008-11-26T13:46:13.333 に答える
0

副作用は悪い考えですが、害はありません。副作用がある場合、基本的に 2 つの操作を行っています。これらの操作を 2 つの関数に分割することをお勧めします。これにより、コードの保守が容易になり、別々に実行できるようになります。

この場合、問題のあるファイルをフォルダから移動し、他のファイルを問題のないファイルに移動します。これらの操作を分離することで、適切なファイルを選択せず​​に不適切なファイルを移動したり、不適切なファイルを移動せずに適切なファイルを操作 (カウントなど) したりできます。コードもより区分化されるため、必要に応じてこれらの操作の 1 つを最適化することが容易になります。

于 2008-11-26T14:01:22.897 に答える
0

ありがとうございます。迅速な対応!

イテレータの副作用は悪い考えであることに同意する必要があります。私が尋ねなければならなかったという事実は、においを示しています。私のスパイディセンスに耳を傾けるべきだった。

私が尋ねた主な理由は、私の副作用が主なタスクからかなり分離されていて、イテレータ内にきちんとカプセル化されていたからだと思います。ただし、それはまだ隠された機能であり、あまり良くありません。

また、ビジターのアイデアをイテレータと混同したと思いますが、これも良い考えではありません。

それ以来、すべてのファイルの元のシーケンスから 2 つのシーケンスを生成するように実装を変更しました。より明確で直感的な方法でそれらを処理できるようになりました。万歳。

そのため、実世界ではまだイテレータを使用していません。しかたがない。

ありがとう!マット

于 2008-11-26T13:56:13.110 に答える
0

一般的なケースについてはコメントしませんが、あなたの場合は危険だと思います。インターフェースの品質の良い指標は、インターフェースを正しく使用するのがどれだけ簡単で、間違って使用するのがどれだけ難しいかです。

この指標を適用すると、設計のスコアは非常に低くなります。これは、誤って使用するのが信じられないほど簡単であるためです。つまり、2 回反復するだけです。

私は実際には、Jon よりもさらに進んで、次のように言います。役に立つかもしれませんが、この間違った使い方をすることの代償は高すぎるかもしれません。一方、ユーザーが意図的に選択した場合、その結果に対処しなければならないと主張することもできます。

于 2008-11-26T18:58:38.210 に答える
0

実際には、イテレータに副作用が隠れているという事実よりも、差し迫った懸念があると思います。つまり、反復しているコレクションのメンバーシップを変更しています。副作用にコードの悪臭がなかったとしても、これは注意が必要です。コレクションから何かを削除すると壊れる、賢明に見えるかもしれないこれを実装する方法があります(ファイルリストをキャッシュし、イテレータをリセットするときにそれを再利用します)。

于 2008-11-26T18:53:17.190 に答える