メソッドが事実上フィールドのnullチェックであることをC#のnull可能参照に通知できますか


14

次のコードを検討してください。

#nullable enable
class Foo
{
    public string? Name { get; set; }
    public bool HasName => Name != null;
    public void NameToUpperCase()
    {
        if (HasName)
        {
            Name = Name.ToUpper();
        }
    }
}

Name = Name.ToUpper()で、Nameがnull参照の可能性があるという警告が表示されますが、これは明らかに正しくありません。HasNameをインライン化することでこの警告を解決できるため、条件は(Name!= null)になります。

HasNameからの真の応答がNameにnull可能でない制約を意味することをコンパイラーに指示する方法はありますか?

HasNameは実際により多くのことをテストする可能性があり、いくつかの場所で使用したり、APIサーフェスのパブリック部分になる可能性があるため、これは重要です。nullチェックを独自のメソッドに組み込む理由はたくさんありますが、そうすることでnull可能な参照チェッカーが機能しなくなるようです。


1
IMO HasValueは、null許容型で使用する必要がありますnull。チェックしないでください。それはおそらくあなたの問題に影響を与えません。
fredrik

私はあなたのために、あなたはコードを#nullable disableその時#nullable enableまたはその後でラップすることができると思いますrestoredocs.microsoft.com/en-us/dotnet/csharp/…)。
GaryNg

5
「dammit」!演算子を使用できます。if(HasName) { Name = Name!.ToUpper(); }
Jan Paolo Go

1
マルチスレッドアプリケーションの場合、HasNameチェックの後にNameをnullにして、プロパティに戻る代わりにローカルで変数を使用すると(プロパティがゲッターで何を行うかを知っている)、いくつかのファンキーなバグが発生します(覚えておいてください)これが多く発生したイベントハンドラーの使用)
XIU

回答:


3

からさまざまな属性を調べましたが、System.Diagnostics.CodeAnalysis該当するものが見つからなかったため、非常に残念です。あなたが望むものに到達できる最も近いものは次のようです:

public bool TryGetName([NotNullWhen(true)] out string? name)
{
    name = Name;
    return name != null;
}

public void NameToUpperCase()
{
    if (TryGetName(out var name))
    {
        Name = name.ToUpper();
    }
}

かなり扱いにくいように見えます。null可能な属性について、MSDNのドキュメントを参照しください。きちんとしたものが見つかる可能性があります。


2
より多くの属性またはtypescriptのアサーションのようなものが必要なようです
Stilgar '24年

私が恐れていたように、本当の答えは「いいえ、c#はまだそれをしていない」と思われるため、これを答えとして選択します。
John Melville

@JohnMelville私もそのような機能の提案を見つけることができなかったので、これがすぐに変わるとは思えません。
V0ldek

2
@XIUコンパイラはこの点ですでに緩いです。行う場合if(Name != null) return Null.ToUpper()、技術的にはTOCTOUの競合状態であっても、null逆参照の警告は表示されません。Mads Torgersenがそれをどのように考慮したかについて話したのを覚えていますが、それは非常に多くの誤検知を生成し、null許容参照型機能全体が実質的に役に立たなくなります-プロパティが別のスレッドによって変更されない時間の99%。したがって、必要なことは、このプロパティのチェックが別のプロパティのnullのチェックとして扱われるようにする属性を作成することだけです。
V0ldek

2
「これに対する提案が見つからない」問題を修正しました。(github.com/dotnet/csharplang/issues/2997)幸運を祈ります。
John Melville

-10

文字列は参照型であり、nullable(egなどint?)はnullable値型です。したがって、これを実際に行うことはできませんstring? myString。あなたが必要なのはこれです:

class Foo
{
    public string Name { get; set; }
    public bool HasName => !String.IsNullOrEmpty(Name);  ////assume you want empty to be treated same way as null
    public void NameToUpperCase()
    {
        if (HasName)
        {
            Name = Name.ToUpper();
        }
    }
}

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