DTOにnull許容参照型を使用するためのベストプラクティス


20

DynamoDBテーブルから読み取ることで入力されるDTOがあります。現在、次のようになっているとします。

public class Item
{
    public string Id { get; set; } // PK so technically cannot be null
    public string Name { get; set; } // validation to prevent nulls but this doesn't stop database hacks
    public string Description { get; set; } // can be null
}

これに対処するためのベストプラクティスはありますか?Dynamo SDK(およびその他)のORMでうまく機能しないため、パラメーターなしのコンストラクターは避けたいと思います。

これはPKであり、nullにpublic string Id { get; set; } = "";なることないため、これが発生することないため、書くのは奇妙に思えIdます。""とにかく何とかしてもどう使うのでしょうか?

これに関するベストプラクティスはありますか?

  • string?ヌルにすることはできなくてもヌルになる可能性があるとすべてにマークを付ける必要があります。
  • 私は初期化すべきであるIdNameして""、彼らはのでべきでヌルと、このショーになることはありません意図は、たとえ""使用されることはありませんでしょう。
  • 上記のいくつかの組み合わせ

注意:これはC#8のnull許容参照型に関するものです。


少し汚れていますが#pragma warning disable CS8618、ファイルの上部で平手打ちできます。
二十

7
= ""を使用= null!するのではなく、を使用して、実際には効果的でないことがわかっているプロパティを初期化できますnull(コンパイラーがそれを知る方法がない場合)。Description合法的にできる場合はnull、それを宣言する必要がありstring?ます。または、DTOのnull 可能性チェックがヘルプよりも厄介な場合は、単にタイプを#nullable disable/ #nullable restoreにラップして、このタイプのみのNRTをオフにすることができます。
Jeroen Mostert、

@JeroenMostert答えにしてください。
Magnus

3
@マグナス:「ベストプラクティス」を求める質問には答えたがらない。そのようなことは広く主観的です。OPが私のコメントを使用して独自の「ベストプラクティス」を開発できることを願っています。
Jeroen Mostert

1
@IvanGarcíaTopete:主キーに文字列を使用するのは珍しいことであり、状況によっては推奨されない場合もあることに同意しますが、OPのデータ型の選択は質問とはあまり関係ありません。これは、主キーではない必須のnull不可の文字列プロパティ、または複合主キーの一部である文字列フィールドにも同様に簡単に適用でき、問題は依然として解決されません。
Jeremy Caney

回答:


12

オプションとして、defaultリテラルをnull forgiving operator

public class Item
{
    public string Id { get; set; } = default!;
    public string Name { get; set; } = default!;
    public string Description { get; set; } = default!;
}

DTOはDynamoDBから入力されるため、MaybeNull/NotNull 後置条件属性を使用してnullの可能を制御できます

  • MaybeNull nullにできない戻り値はnullになることがあります。
  • NotNull null許容の戻り値がnullになることはありません。

ただし、これらの属性は、注釈が付けられたメンバーの呼び出し元のnull許容分析にのみ影響します。通常、これらの属性は、メソッドの戻り値、プロパティ、インデクサーのゲッターに適用します。

したがって、すべてのプロパティをnullにできないものと見なし、MaybeNull属性で装飾して、可能なnull値を返すことを示すことができます

public class Item
{
    public string Id { get; set; } = "";
    [MaybeNull] public string Name { get; set; } = default!;
    [MaybeNull] public string Description { get; set; } = default!;
}

次の例は、更新されたItemクラスの使用法を示しています。ご覧のとおり、2行目には警告は表示されませんが、3行目には警告が表示されます

var item = new Item();
string id = item.Id;
string name = item.Name; //warning CS8600: Converting null literal or possible null value to non-nullable type.

または、すべてのプロパティをnull許容のプロパティにしてNoNull、戻り値ができないことを示すために使用することもできますnullId例)

public class Item
{
    [NotNull] public string? Id { get; set; }
    public string? Name { get; set; }
    public string? Description { get; set; }
}

警告は前の例と同じになります。

同様に機能する入力パラメーター、プロパティ、インデクサーセッターのAllowNull/DisallowNull 前提条件属性もあります。

  • AllowNull nullにできない入力引数はnullになる可能性があります。
  • DisallowNull null可能な入力引数はnullであってはなりません。

あなたのクラスはデータベースから読み込まれるので、私はそれがあなたを助けるとは思わないが、それらを使ってプロパティセッターのnull可能性を制御することができます。

[MaybeNull, AllowNull] public string Description { get; set; }

そして二番目に

[NotNull, DisallowNull] public string? Id { get; set; }

ポスト/前提条件のいくつかの役立つ詳細と例は、このdevblog記事にあります


6

このシナリオの教科書の答えはstring?Idプロパティにを使用することですが、属性で装飾することもでき[NotNull]ます。

public class Item
{
  [NotNull] public string? Id { get; set; }
  public string Name { get; set; }
  public string? Description { get; set; }
}

参照:ドキュメントによると[NotNull]属性は「対応する型で許可されていても、出力がnullではないことを指定します。」

それで、ここで正確に何が起こっているのですか?

  1. まず、string?戻り値の型により、構築中にプロパティが初期化されていないため、デフォルトでになることをコンパイラが警告しないようにしますnull
  2. 次に、この[NotNull]プロパティは、nullを設定できない変数にプロパティを割り当てたり、逆参照を試みたりする際の警告を防ぎます。これは、コンパイラの静的フロー分析に、実際にはこのプロパティは決してないことを通知するためですnull

警告: C#のnull可能性コンテキストが関係するすべてのケースと同様に、nullここに値を返すことを技術的に妨げるものはなく、したがって、いくつかのダウンストリーム例外が発生する可能性があります。つまり、すぐに使えるランタイム検証はありません。これまでに提供されたすべてのC#はコンパイラの警告です。紹介[NotNull]すると、ビジネスロジックについてのヒントを与えることで、警告を効果的に上書きします。したがって、プロパティにで注釈を付けるときは[NotNull]、「これはPKであるため決して発生せず、Idnullになることありない」という責任を負うことになります。

あなたがそのコミットメントを維持するのを助けるために、あなたは可能さらにとプロパティに注釈を付けたい[DisallowNull]属性:

public class Item
{
  [NotNull, DisallowNull] public string? Id { get; set; }
  public string Name { get; set; }
  public string? Description { get; set; }
}

参照:ドキュメントによると[DisallowNull]属性は「null対応するタイプで許可されている場合でも、入力として許可されないことを指定します。」

値がデータベース経由で割り当てられているので、これはあなたのケースでは適切ではないかもしれませんが、[DisallowNull]あなたが今までに割り当てようとすると、属性はあなたに警告を与えるnullに(可能な)値をIdそれがためにのための戻り値の型が、そうでないことができるにもかかわらず、 null。その点において、Id作用する正確ようにstringしながら、限りC#の静的フロー分析に関してはまた、値がオブジェクトの構造及び性質の集団の間で初期化されていないままであることを可能にします。

注:他の人が述べたように、またはのIdデフォルト値を割り当てることにより、実質的に同じ結果を得ることができます。確かに、これはやや文体的な好みです。コンパイラーをシャットダウンする方法として悪用するのは簡単ですが、より明示的で詳細な制御を提供できるため、私はnullabilityアノテーションを使用することを好みます。値でプロパティを明示的に初期化すると、たとえその値がデフォルトであっても、その値を使用するつもりがないことがわかっている場合は、問題が発生します。default!null!!


-2

文字列は参照型であり、常にNULL可能です。特別なことをする必要はありません。このオブジェクトタイプを別のオブジェクトタイプにマップする場合にのみ問題が発生する可能性がありますが、後で処理できます。


8
彼はC#8のNullable参照型について話している
Magnus
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.