C#でnullチェック

1
2
3
4
5
6
7
8
9
public Control GetParentParent(Control control)
{
if (control != null) {
if (control.Parent != null) {
return control.Parent.Parent;
}
}
return null;
}

インスタンスメソッドを呼び出すときに気をつけないといけないことのひとつにオブジェクトがnullかどうかをチェックしなければならないことがあります。チェックを怠るとNullReferenceExceptionが発生してしまいます。しかし、nullチェックをするとコード行数が増え、見通しが悪くなります。

例えばコントロールの親の親を取得するメソッドGetParentParentはおおよそ右のコードになります。親の親に該当するものがなければnullを返します。オブジェクトをたくさんたどればそれだけ条件分岐が増えていきます。

1
2
3
4
5
6
7
8
9
public static void _<T>(this T obj, Action<T> action)
{
if (obj != null) action(obj);
}

public static TResult _<TSource, TResult>(this TSource obj, Func<TSource, TResult> func)
{
return obj == null ? default(TResult) : func(obj);
}

これを簡単に書くためにちょっとしたヘルパーメソッドを作成します。コードを短くするために名前をアンダースコアにしてあります。次の1つめの拡張メソッドはobjがnullの場合actionを実行しません。ジェネリックを使っていますのでactionとつじつまが合っていればどんな型でも渡せます。2つめのメソッドは値を返すものでobjがnullの場合funcを実行しないで返値の型TResultの既定値を返します。TResultがValueTypeでなければnullを返します。インスタンスメソッドの場合はオブジェクトがnullの場合にメソッド呼び出しができませんが、拡張メソッドは静的メソッドを第1引数のメソッド呼び出し形式で呼び出せるシンタックスシュガーに過ぎませんので引数objにnullが渡されてもエラーにならないのです。

1
2
3
4
public Control GetParentParent(Control control)
{
return control._(c => c.Parent)._(c => c.Parent);
}

このヘルパーメソッドを利用するとGetParentParentはLINQ同様メソッドチェーン1行で記述できます。

HaskellにはMaybeモナド、Delphi Prismにはコロン演算子がありますが、C#でも上記のヘルパーメソッドで簡潔に書けるようになります。

Visual Basicではアンダースコアが行連結文字になっていますので別の名前を付けなければなりません。

1
2
3
4
public Control GetParentParent(Control control)
{
return control?.Parent?.Parent;
}

C# 6.0 (Visual Studio 2015) では Null条件演算子(?.)が導入されました。

参照