BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース C# 9: シンプルになったパラメータnullバリデーション

C# 9: シンプルになったパラメータnullバリデーション

原文(投稿日:2020/06/15)へのリンク

先回のレポート"C#の今後 — パラメータnullバリデーションの簡略化"の時、この機能には属性やコンパイルフラグ、あるいはILウィービングによるフルスケールAPIなど、競合する提案の存在という課題があった。結果的にそれらはすべて、非nullパラメータを検証するために必要なコード量をわずか1文字に削減するという、最小限に設定された機能提案によって破棄されることになった。

否定演算子"!"をパラメータリスト内の任意の識別子の直後に置くことで、C#コンパイラが、そのパラメータの標準的なnullチェックを行うコードを出力するようになる。例えば、

void M(string name!) {
    ...
}

上記のコードは、次のように変換される。

void M(string name!) {
    if (name is null) {
        throw new ArgumentNullException(nameof(name));

    }
    ...
}

 

ルールは極めて単純だ。

  • 他のコードより前、関数の先頭に、関数シグネチャ内のパラメータと同じ順番で、nullチェックが挿入される。
  • 実行されるのは参照型等価のnullチェックで、==演算子のオーバーロードは無視される。
  • コンストラクタで使用された場合は、ベースクラスのコンストラクタがコールされた後に行われる。
  • イテレータの場合には、"nullチェックは下位のメソッドではなく、常に最初のコールにおいて行わなければならない"。
  • nullを設定できないパラメータ(structや非マネージド)にnullチェックが行われた場合は、コンパイラエラーが発生する。
  • 対応する実装のないパラメータ(抽象メソッドやデリゲート、インターフェースメソッド、パーシャルメソッドなど)にnullチェックが行われた場合も、コンパイルエラーになる。
  • outパラメータに対するnullチェックはコンパイラエラーとなる。
  • 明示的にnull可能なパラメータにnullチェックが行われた場合(string? x!)、コンパイラが警告を発する。予想されるように、サブクラスではベースクラスより厳密にすることが可能である。
  • nullデフォルト値を持つ省略可能なパラメータにnullチェックが行われた場合は、コンパイラが警告を発する。

コンストラクタのルールに関しては、ベースクラスのコンストラクタをコールする前にパラメータチェックが可能なように考慮されている。これは.NETでは常に許容されているので、間違いなく望ましい方法だ。しかしながら、C#の構文ではこの機能を公開していないので、この機能を使用しなければ作成できないコードの生成は望んでいなかった。

テスト計画では、ジェネリクスについて次のようなシナリオが示されている。

void M<T>(T value!) { } is OK
void M<T>(T value!) where T : struct { } is an error
void M<T>(T value!) where T : unmanaged { } is an error
void M<T>(T value!) where T : notnull { } is OK
void M<T>(T value!) where T : class { } is OK
void M<T>(T value!) where T : SomeStruct { } is an error
void M<T>(T value!) where T : SomeClass { } is OK

このデザインの問題点のひとつは、valueパラメータが明示的でないため、プロパティの検証がサポートされないことだ。Orthoxerox(ユーザ名)がこのシナリオに対して、setキーワードに否定演算子を適用する回避策を提案している

public Foo Foo {get; set!;}

public Bar Bar {
    get { return bar; }
    set!{ bar = value; DoSomethingElse(); }
}

 

この記事に星をつける

おすすめ度
スタイル

BT