オブジェクトの深いところの値を例外出す可能性無しにとってきたい
仕事でメンバーの数的にすごいでっかいオブジェクト扱うんですよ、それで、それのすごいばらばらな場所にある値をとってきてASP.NETの画面に出したい。100個位。という事情があって、でも、たとえば、a.b.c[0].dとかいう値を表示したいとして、絶対に例外でないように書くといちいちnullと配列の長さチェックしなければいけないわけですよ。全部コードビハインドのプロパティにしてるから、例外でるとDataBind()のところまで飛ばされちゃって、以降の値が表示されなくなるし、それだと困るから。
で、途中の値がnullでとれないこと自体はまぁどうでも良いというか、どうでもよくは無いんだけど無いものは無いしログにでもだしといて、という感じなので、いままでは、
if(instance_a.b == null || instance_a.b.c == null || instance_a.b.c.Length == 0 || instance_a.b.c[0].d == null) Console.WriteLine("どこかがnullかもしくは配列の長さがおかしかったので、instance_a.b.c[0].dは取得できませんでした!!"); else Console.WriteLine(instance_a.b.c[0].d.s1);
とか、
try { Console.WriteLine(instance_a.b.c[0].d.s1); } catch(NullReferenceException) { Console.WriteLine("どこかがnullだったので、instance_a.b.c[0].dは取得できませんでした!!"); } catch(IndexOutOfRangeException) { Console.WriteLine("どこかで配列インデックスがおかしかったので、instance_a.b.c[0].dは取得できませんでした!!"); }
してたんだけど、あれだね!! Expressionてすごいね! まぁ、デリゲートでも別に出来たみたいなんだけど、こう出来るね。
static string Getda<T>(T a, Expression<Func<T, String>> x) { try { return x.Compile()(a); } catch(NullReferenceException) { return string.Format("どこかがnullだったので、{0}は取得できませんでした!!", x.Body); } catch(IndexOutOfRangeException) { return string.Format("どこかで配列インデックスがおかしかったので、{0}は取得できませんでした!!", x.Body); } }
呼び出す側は、一行だ……。
Console.WriteLine(Getda(instance_a, a => a.b.c[0].d.s1));
すげー、と思って会社の人とかに見せたんだけどあんまり評判よくなかった。拡張メソッドにすると
Console.WriteLine(instance_a.Getda(a => a.b.c[0].d.s2));
とか書けて夢のようなのに……。
Complileとか、例外出るところとかが印象悪いみたいで、基本nullになってるとことか無いし保険みたいなもんだから、例外のほうは100個全部例外出ても僕のマシンで0.01秒とかだけどなー、やっぱ無しなのかな。