要素は2つ。ループは3回

後輩が奇妙な質問を投げてきた。

リストの要素は2個なんですけど、3回ループしてるんですけど、なんかわかりますか?

なんぞそれは?とか思ったけど、よくよく調べたら、共通メソッドがそういう動きだっただけの話だった。
namespace TawamureDays {

class Utils {

/// <summary>
/// (List)引数リストがnull或いは空リストかどうかを判定します。
/// </summary>
/// <param name="list">リスト</param>
/// <returns>true:null或いは空リスト</returns>
public static bool IsNullOrEmpty(IEnumerable list) {

if (list == null) {
return true;
}

foreach (var element in list) {
return false;
}

return true;
}
}
}
引数のlistがnull又は要素が0の空リストかどうかを判定するメソッドである。これを↓のような感じで使っていた
if (Util.IsNullOrEmpty(list)) {
return;
}

foreach (var element in list) {
//...処理
}
これで問題なし!と思っていたし、実際通常のケースでは問題ない。ただ、後輩君の実装では、問題点が露見した形となった。
var enumerator = list.Select(element => new Element2 {...});

if (Util.IsNullOrEmpty(enumerator)) {
return;
}

foreach (var element in enumerator) {
//...処理
}
見た目問題ないようだけど、IsNullOrEmptyのメソッド内で、最低1回ループしてしまう。この段階で、Select内のFuncが実行され、Element2クラスのインスタンスを生成し、その後何もしない(というか無駄に1つ生成してしまう)。要するに、null判定で1回余分に呼び出される事になる。後輩君のコードは、Func内ののElement2を生成した段階で、元ネタとなるelementの内部情報を書き換えてしまうらしく、思ったような動きにならなかったようだ。結局、こんな感じに直した。
//listのnull判定は事前に行う。
var list2 = list.Select(element => new Element2 {...}).ToArray();

if (Util.IsNullOrEmpty(list2)) {
return;
}

foreach (var element in list2) {
//...処理
}
共通系を直しても良いのだけど、要素の数がすごい数だったとき、どうなんだろ?とか思うし、影響範囲もでかいので、おいそれとできない。そうはいえど、やはりクラスやメソッドは、使ってナンボである、という事を実感した日だった。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: C# | コメント: 2 | トラックバック: 0


この記事へのコメント

IEnumerable は
IEnumerable は、基本的に一度しか実行してはいけない型です。
Resharper 等の静的検証を充実させる Visual Studio 拡張をインストールしておくと、IEnumerable を複数実行する場合に警告してくれるので、こういうミスを発見できます。
おすすめ。
Re: IEnumerable は
> IEnumerable は、基本的に一度しか実行してはいけない型です。
> Resharper 等の静的検証を充実させる Visual Studio 拡張をインストールしておくと、IEnumerable を複数実行する場合に警告してくれるので、こういうミスを発見できます。
> おすすめ。
おお。情報ありがとうございます。
基本的に一度だけの実装なのであれば、共通メソッドの修正も検討しないと駄目という事ですね。

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m