Kann ich C # nullable Referenzen mitteilen, dass eine Methode effektiv eine Nullprüfung für ein Feld ist?


14

Betrachten Sie den folgenden Code:

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

Auf dem Namen = Name.ToUpper () erhalte ich eine Warnung, dass Name eine mögliche Nullreferenz ist, was eindeutig falsch ist. Ich kann diese Warnung beheben, indem ich HasName einfüge, sodass die Bedingung if (Name! = Null) lautet.

Kann ich den Compiler auf irgendeine Weise anweisen, dass eine echte Antwort von HasName eine Nicht-Nullfähigkeitsbeschränkung für Name impliziert?

Dies ist wichtig, da HasName möglicherweise viel mehr Dinge testet und ich es möglicherweise an mehreren Stellen verwenden möchte oder es ein öffentlicher Teil der API-Oberfläche ist. Es gibt viele Gründe, die Nullprüfung in ihre eigene Methode einbeziehen zu wollen, aber dies scheint die nullbare Referenzprüfung zu beschädigen.


1
IMO sollten Sie HasValuefür einen nullbaren Typ verwenden, nicht dagegen prüfen null. Es hat jedoch wahrscheinlich keinen Einfluss auf Ihr Problem.
Fredrik

Ich denke, für Ihren Fall können Sie Ihren Code #nullable disabledann #nullable enableoder restoredanach erneut umschließen ( docs.microsoft.com/en-us/dotnet/csharp/… ).
GaryNg

5
Sie könnten den !Operator "verdammt" verwenden . if(HasName) { Name = Name!.ToUpper(); }
Jan Paolo Go

1
Bei einer Multithread-Anwendung kann der Name nach der HasName-Prüfung null sein. Wenn Sie die Variable lokal verwenden, anstatt zur Eigenschaft zurückzukehren (wer weiß, was die Eigenschaft in ihrem Getter möglicherweise tut), treten einige funky Fehler auf (denken Sie daran die Verwendung eines Event-Handlers, wo dies viel passiert ist)
XIU

Antworten:


3

Ich habe mich in den verschiedenen Attributen umgesehen System.Diagnostics.CodeAnalysisund konnte nichts zutreffendes finden, was sehr enttäuschend ist. Der nächste Punkt, den Sie erreichen können, scheint zu sein:

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

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

Es sieht ziemlich umständlich aus, ich weiß. Sie können in den MSDN-Dokumenten nach nullbaren Attributen suchen. Vielleicht finden Sie etwas Ordentlicheres.


2
Scheint, als bräuchten wir mehr Attribute oder so etwas wie die Behauptungen von Typoskript
Stilgar

Ich werde diese als Antwort auswählen, da es so aussieht, als ob die eigentliche Antwort, wie ich befürchtet hatte, "nein, c # macht das noch nicht" ist.
John Melville

@JohnMelville Ich konnte auch keinen Vorschlag für eine solche Funktion finden, daher denke ich nicht, dass wir damit rechnen können, dass sich dies bald ändern wird.
V0ldek

2
@XIU Der Compiler ist in dieser Hinsicht bereits lax. Wenn Sie dies tun if(Name != null) return Null.ToUpper(), wird keine Warnung für eine Null-Dereferenzierung angezeigt, obwohl es sich technisch gesehen um eine TOCTOU-Rennbedingung handelt. Ich erinnere mich, dass Mads Torgersen darüber sprach, wie sie das betrachteten, aber es würde so viele Fehlalarme erzeugen, dass die gesamte Funktion für nullfähige Referenztypen praktisch nutzlos wäre - 99% der Zeit werden Ihre Eigenschaften nicht von einem anderen Thread geändert. Sie müssen also nur ein Attribut erstellen, mit dem die Prüfung dieser Eigenschaft als Prüfung einer anderen Eigenschaft auf Null behandelt wird.
V0ldek

2
Ich habe das Problem "Ich kann keinen Vorschlag für dieses Problem finden" behoben. ( github.com/dotnet/csharplang/issues/2997 ) Wünsch mir Glück.
John Melville

-10

String ist ein Referenztyp und nullable (z. B. int?) ist nullable Werttypen. Das kann man also nicht wirklich machen string? myString; Was Sie brauchen, ist Folgendes:

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();
        }
    }
}

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.