Puis-je dire aux références nullables C # qu'une méthode est effectivement une vérification nulle sur un champ


14

Considérez le code suivant:

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

Sur Name = Name.ToUpper (), je reçois un avertissement indiquant que Name est une référence null possible, ce qui est clairement incorrect. Je peux remédier à cet avertissement en insérant HasName afin que la condition soit if (Name! = Null).

Existe-t-il un moyen de dire au compilateur qu'une vraie réponse de HasName implique une contrainte de non-nullité sur Name?

Ceci est important car HasName pourrait en fait tester beaucoup plus de choses, et je pourrais vouloir l'utiliser à plusieurs endroits, ou il pourrait être une partie publique de la surface de l'API. Il existe de nombreuses raisons de vouloir factoriser la vérification nulle dans sa propre méthode, mais cela semble casser le vérificateur de référence nullable.


1
IMO vous devez utiliser HasValuesur un type nullable, ne pas le vérifier null. Cela n'affecte probablement pas votre problème.
Fredrik

Je pense que pour vous cas, vous pouvez vous envelopper code avec #nullable disablepuis #nullable enableou restoreencore par la suite ( docs.microsoft.com/en-us/dotnet/csharp/... ).
GaryNg

5
vous pouvez utiliser l' !opérateur "dammit" . if(HasName) { Name = Name!.ToUpper(); }
Jan Paolo Go

1
pour une application multi-thread, vous pourriez avoir le nom étant nul après la vérification de HasName, utiliser la variable localement au lieu de revenir à la propriété (qui sait ce que la propriété pourrait faire dans son getter) va donner des bugs géniaux (rappelez-vous l'utilisation d'un gestionnaire d'événements lorsque cela s'est produit beaucoup)
XIU

Réponses:


3

J'ai regardé les différents attributs de System.Diagnostics.CodeAnalysiset je n'ai rien trouvé qui soit applicable, ce qui est très décevant. Le plus proche de ce que vous voulez semble être:

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

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

Ça a l'air assez lourd, je sais. Vous pouvez consulter les documents MSDN pour les attributs nullables , peut-être trouverez-vous quelque chose de plus propre.


2
Il semble que nous ayons besoin de plus d'attributs ou de quelque chose comme les assertions de dactylographie
Stilgar

Je vais choisir celui-ci comme réponse, car il semble que la vraie réponse, comme je le craignais, est "non, c # ne le fait pas encore".
John Melville

@JohnMelville Je n'ai pas non plus été en mesure de trouver une proposition pour une telle fonctionnalité, donc je ne pense pas que nous pouvons nous attendre à ce que cela change de si tôt.
V0ldek

2
@XIU Le compilateur est déjà laxiste à cet égard. Si vous le faites if(Name != null) return Null.ToUpper(), il n'y aura aucun avertissement pour une déréférence nulle, même s'il s'agit techniquement d'une condition de concurrence TOCTOU. Je me souviens que Mads Torgersen parlait de la façon dont ils considéraient cela, mais cela générerait tellement de faux positifs que la fonctionnalité entière des types de référence annulables serait effectivement inutile - 99% du temps, vos propriétés ne seront pas modifiées par un autre thread. Donc, tout ce que vous avez à faire est de créer un attribut qui ferait que la vérification de cette propriété soit traitée comme une vérification de null sur une autre propriété.
V0ldek

2
J'ai résolu le problème "Impossible de trouver une proposition pour ce problème". ( github.com/dotnet/csharplang/issues/2997 ) Souhaitez-moi bonne chance.
John Melville

-10

La chaîne est un type de référence et nullable (par exemple int?) est un type de valeur nullable. Vous ne pouvez donc pas vraiment faire cela string? myString; Vous avez besoin de ceci:

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.