2015年9月15日火曜日

[コラム]C#7-Nullabilityについて-


今年の4月頃、C#7に向けた作業予定リストが公開されました。
 C# 7 Work List of Feature # 2136
それによるとC#7から、Null非許容型の追加や、コンパイラによる構文チェックに関する仕様が変わるようなので、その特徴や使い方をまとめてみました。
※今回はC# 7 Work List of Feature # 2136のソースを使用しています。

■C#のNull許容型


C#において、通常、int型のような値型はnull値を持てません。
int a = null; // Compiler Error
しかしnullable型(null許容型)を使用すれば、値型にもnullを代入することができます。
nullable型は型名の後ろに「?」を付けることで使用できます。
int? a = null; // OK.
null許容型の効果が強く発揮されるのは、データベースなどで値が割り当てられていない要素などを操作する時などでしょう。また、boolean型にtrue,falseだけでなくnull値を割り当てられるのも便利です。
このようにnullableの概念は以前からC#にあったのですが、今回は仕様変更に伴い、「null非許容型」が追加されるようです。

■C#7からのNull許容型/非許容型


null非許容型とはnullが割り当てられることを許可しない型のことです。
null非許容型は型名の後ろに「!」を付けることで使用できます。
int! a;
null非許容型は、もちろんnullそのものも割り当てることはできませんし、「nullの可能性のあるもの」も参照できません。
このルールはコンパイラによって遵守されるため、コンパイルが通った場合、null非許容型のものを参照してnullエラーは発生し得ません。
Dog! mandatoryDog1 = myNullableDog; // Compiler Error - the nullable reference may be null.
Dog! mandatoryDog2 = myGeneralDog; // Compiler Error - the general reference may be null.
Dog? nullableDog1 = myMandatoryDog; // OK.
Dog? nullableDog2 = myGeneralDog; // Compiler Error - makes an assumption about the intent of the general reference (maybe it is conceptually mandatory, rather than conceptually nullable as assumed here).
Dog generalDog1 = myMandatoryDog; // Compiler Error - loses information about the intent of the mandatory reference (the general reference may be conceptually mandatory, or may be conceptually nullable if the intent is that it could later be made null).
Dog generalDog2 = myNullableDog; // Compiler Error - loses the safety of the nullable reference.

null非許容型の考え方は、最近ではSwiftなどでも採用されています。
SwiftではOptional型、非Optional型としてこの概念を取り入れており、C#と同様に「?」と「!」を付けます。
Swiftで非Optional型にOptional型を参照させる場合、プログラマ側が「この変数は絶対にnullじゃないですよ」と保障しながら、実際にはnullを参照させてExceptionを発生させてしまうこともあり得ます。
その辺がC#でどのようになるかは不明ですが、そんなプログラマ側のミスまでコンパイラ側で面倒を見てくれるようになれば喜ばしいですね。

■既存のコードの修正が必要か


このような言語仕様の変更の際に気になるのは、既存のコードが動くのかどうかという点ですが、この件に関しては「既存のコードもほとんど問題なく動く」そうですが、nullの安全性が保障されていない参照に関してはコンパイルエラーが発生する可能性があるとのことで、やはり修正が必要にはなるでしょう。

■「check」キーワード


新たに「check」キーワードが追加されるようです。
checkキーワードは以下のようにして使用します。
Dog? nullableDog = new Dog("Nullable");

nullableDog.Bark(); // Compiler Error - cannot dereference nullable reference (yet).

check (nullableDog)
{
    // This code branch is executed if the reference is non-null. The compiler will allow methods to be called and properties to be accessed.
    nullableDog.Bark(); // OK.
}
else
{
    nullableDog.Bark(); // Compiler Error - we know the reference is null in this context.
}

使い方としては従来のnullチェックと同じような感じですが、elseに入った時点で中身がnullであることは確かに明らかであり、これをコンパイラが弾いてくれるというのは便利です。

■コンストラクタのNullチェック


このようにコンパイラによるnullの管理を行う中で、しかしクラスのフィールドにはnullである可能性がある変数が存在してしまいます。
この問題に対しては、フィールドが初期化されるまでnull非許容型への参照は許可しないという形になるようです。
public class Car
{
    public Engine! Engine { get; private set; }

    public Car(Engine! engine)
    {
        Engine.Start(); // Compiler Error
        CarInitializer.Initialize(this); // Compiler Error - the 'this' reference could be used to access Engine methods and properties
        Engine = engine;
        // Can now use Engine and 'this' at will
    }
}

■感想


Nullエラーはプログラミングに慣れてきてもついつい起こしてしまうExceptionの一つです。
Nullは強力ですがその取扱いには常に注意を払う必要があります。
そこにかけるコストを少しでも軽減し、またコードの安全性を保つためにNull非許容型を取り入れコンパイラで監視するという考え方は理にかなっていると思いますし、習得しておいて損はないと思います。
140 180 C# , コラム

記載されている会社名、および商品名等は、各社の商標または登録商標です。

0 コメント:

コメントを投稿

Related Posts Plugin for WordPress, Blogger...