Archive for 2月, 2012

煩雑になった定義部分を省略する

前回の記事の続きです。Tupleを使うのがいいのか悩んでいた面もあったので、コードが冗長になっていました。
以下、記述量を減らしたパターンです。

            Func<Func<bool>, string, Tuple<Func<bool>, string>> te = (f, s) => Tuple.Create(f, s);
            var 確認事項2 = new List<Tuple<Func<bool>, string>>{
                te((()=>a==b),"一致ダメ"),
                te((()=>a>b),"aが大きくてはダメ"),
                te((()=>b > a * 10),"bが大きすぎてもダメ"),
            };

一見、最初に書くのが面倒くさそうなイメージがありますが、各データのイメージがあるので書けます。後からメンテナンスするときは、引数部分だけ検討すればいいのでお手軽です。

エラー処理で行いがちな、条件判定ブロックを整理する

エラー判定を行うときに、簡単に書いてしまうと下記の記述になることがあります。

            int a = 5;
            int b = 10;

            if (a == b) {
                Console.WriteLine("一致ダメ");
                return;
            }

            if (a > b) {
                Console.WriteLine("aが大きくてはダメ");
                return;
            }

            if (b > a * 10) {
                Console.WriteLine("bが大きすぎてもダメ");
                return;
            }

return;が入っていることから、これはこれ以上まとめようがないと思っていました。
ただこれをじっと見ていたら、次のまとめ方に気づきました。

            var 確認事項 = new List<Tuple<bool, string>>{
                Tuple.Create((a==b),"一致ダメ"),
                Tuple.Create((a>b),"aが大きくてはダメ"),
                Tuple.Create((b > a * 10),"bが大きすぎてもダメ"),
            };

            foreach (var s in 確認事項) {
                if (s.Item1) {
                    Console.WriteLine(s.Item2);
                    return;
                }
            }

ここで、次のネタが発生します。
aとbの大小関係を評価するタイミングはどこなのか? というネタです。
上記の例では、変数への代入時ですので、この後a,bの値が変更になるコードの場合には、意図した動作にはなりません。

そういったケースでは次の書き換えを行います。

            var 確認事項2 = new List<Tuple<Func<bool>, string>>{
                Tuple.Create((Func<bool>)(()=>a==b),"一致ダメ"),
                Tuple.Create((Func<bool>)(()=>a>b),"aが大きくてはダメ"),
                Tuple.Create((Func<bool>)(()=>b > a * 10),"bが大きすぎてもダメ"),
            };

            foreach (var s in 確認事項2) {
                if (s.Item1()) {
                    Console.WriteLine(s.Item2);
                    return;
                }
            }

ラムダ式の評価タイミングが意図したタイミングに合うと思います。
ちょっと定義部分の記述が多すぎるので、簡潔にしたいところです。
同様のパターンで条件判定の後に異なる動作を入れる場合は、stringの部分をラムダ式にしてしまえば実現できます。

大きくなりすぎたクラスを整理するには

リファクタリングを行っていると、大幅な書き換えを行ってしまったことにより、旧コードのメソッド群が作業の邪魔になることがあります。
旧コードは消してしまえればそれに越したことは無いのですが、なんらかの心理的抵抗があるのも事実です。
見たくない範囲を#region で隠してしまったりもするのですが、何かの拍子に展開されてしまって、いちいち癇に障ります。
そんなときの、いかにも実践的な泥臭い解決方法。

partial class を1つ新設し、本来なら消してしまうようなコードをまとめてそちらに移動する。

乱暴に見えますが、本気でメンテナンスしたいファイルの(見た目の)行数が減るので作業効率があがります。
上記の変更は、コピーさえ失敗しなければ、プログラムの動作は変わりません。