web-dev-qa-db-ja.com

ヌル可能参照タイプとオプションパターン

オプションパターン と組み合わせてnull不可の参照タイプをどのように使用できますか?

MyOptionsという名前のオプションモデルがあるとします。

これらのオプションを必要とするサービスはIOptions<MyOptions> optionsをコンストラクタに注入しました。

オプションの構成は、次のようにIServiceCollectionで行われます。

services
    .AddOptions<MyOptions>()
    .Configure(options =>
    {
        options.Name = "ABC";
    });

現在、問題はMyOptionsの定義にあります:

public sealed class MyOptions
{
    public string Name { get; set; }
}

これは警告を生成します:

CS8618 null可能ではないプロパティ 'Name'は初期化されていません。プロパティをnull許容として宣言することを検討してください。

  1. Nameをnullにできるようにしたくないので、従来のnullチェックをどこにでも配置する必要があります(これはnullできない参照タイプの目的に反します
  2. MyOptionsメソッドがオプションインスタンスを作成するため、nameクラスをnull不可のConfigure値で作成するように強制するコンストラクターを作成することはできません
  3. null-forgiving operatorトリック(public string name { get; set; } = null!;)この場合、Nameプロパティが設定されていることを確認できず、nullプロパティにNameが含まれる可能性があります。サービス)

検討し忘れた他のオプションはありますか?

16
huysentruitw

プロパティの予想される動作が、最初はnullを含む可能性があるがnullに設定してはならない場合は、 DisallowNullAttribute を使用してみてください。

#nullable enable

using System.Diagnostics.CodeAnalysis;

public sealed class MyOptions
{
    [DisallowNull]
    public string? Name { get; set; }

    public static void Test()
    {
        var options = new MyOptions();
        options.Name = null; // warning
        options.Name = "Hello"; // ok
    }

    public static void Test2()
    {
        var options = new MyOptions();
        options.Name.Substring(1); // warning on dereference
    }
}
3
Rikki Gibson

ここには2つの選択肢があるようです。最初の方法は、Optionsのチェックを回避するために、空の文字列を使用してnullプロパティを初期化することです(null値の代わりに)。

public sealed class MyOptions
{
    public string Name { get; set; } = "";
}

2つ目は、すべてのプロパティをnull可能なプロパティにし、 DisallowNull 前提条件と NotNull 事後条件を使用してそれらを装飾することです。

DisallowNullは、null許容の入力引数がnullであってはならないことを意味します。NotNull-null許容の戻り値がnullになることはありません。ただし、これらの属性は、注釈が付けられたメンバーの呼び出し元のnull許容分析にのみ影響します。したがって、null可能宣言にもかかわらず、プロパティがnullを返すことも、nullに設定することもできないことを示しています。

public sealed class MyOptions
{
    [NotNull, DisallowNull]public string? Name { get; set; }
}

と使用例

var options = new MyOptions();
options.Name = null; //warning CS8625: Cannot convert null literal to non-nullable reference type.
options.Name = "test";

ただし、次の例では警告は表示されません。オブジェクト初期化子ではnull許容分析がまだ適切に機能していないため、これを参照してください GitHubの問題

var options = new MyOptions { Name = null }; //no warning

プロパティゲッターの場合と同じように、次のサンプルでは、​​null許容の戻り値の型はnullにできないことを示しているため、警告は表示されません。

var options = new MyOptions();
string test = options.Name.ToLower();

しかし、null値を設定して取得しようとすると、警告が生成されます(コンパイラーはそのようなシナリオを検出するのに十分スマートです)

var options = new MyOptions() { Name = null };
string test = options.Name.ToLower(); //warning CS8602: Dereference of a possibly null reference.
3