Posso dire ai riferimenti nullable di C # che un metodo è effettivamente un controllo null su un campo


14

Considera il seguente codice:

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

Su Name = Name.ToUpper () ricevo un avviso che Name è un possibile riferimento null, che è chiaramente errato. Posso curare questo avviso integrando HasName quindi la condizione è if (Name! = Null).

Esiste un modo per indicare al compilatore che una risposta vera da HasName implica un vincolo di non annullabilità su Name?

Questo è importante perché HasName potrebbe effettivamente testare molte più cose e potrei volerlo usare in diversi punti, o potrebbe essere una parte pubblica della superficie dell'API. Ci sono molte ragioni per voler fattorizzare il controllo null nel suo metodo, ma farlo sembra infrangere il controllo di riferimento nullable.


1
IMO che dovresti usare HasValuesu un tipo nullable, non verificarlo null. Tuttavia, probabilmente non influisce sul problema.
Fredrik,

Penso che per il tuo caso, puoi avvolgere il tuo codice con #nullable disablepoi #nullable enableo restoreancora dopo ( docs.microsoft.com/en-us/dotnet/csharp/… ).
Data

5
potresti usare l' !operatore "dammit" . if(HasName) { Name = Name!.ToUpper(); }
Jan Paolo Go

1
per un'applicazione multi-thread, è possibile che Nome sia nullo dopo il controllo HasName, utilizzando la variabile localmente invece di tornare alla proprietà (chissà cosa potrebbe fare la proprietà nel suo getter) darà alcuni bug funky (ricorda l'uso di un gestore di eventi in cui ciò è accaduto molto)
XIU

Risposte:


3

Mi sono guardato intorno ai diversi attributi System.Diagnostics.CodeAnalysise non sono riuscito a trovare nulla di pertinente, il che è molto deludente. Il più vicino che puoi raggiungere a quello che vuoi sembra essere:

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

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

Sembra piuttosto ingombrante, lo so. Puoi guardare i documenti MSDN per attributi nullable , forse troverai qualcosa di più ordinato.


2
Sembra che abbiamo bisogno di più attributi o qualcosa di simile alle affermazioni dei dattiloscritti
Stilgar

Prenderò questo come risposta, perché sembra che la vera risposta, come temevo, sia "no, c # non lo fa ancora."
John Melville,

@JohnMelville Non sono riuscito a trovare neanche una proposta per tale funzione, quindi non credo che possiamo aspettarci che cambi presto.
V0ldek,

2
@XIU Il compilatore è già rilassato in questo aspetto. Se lo fai if(Name != null) return Null.ToUpper(), non ci sarà alcun avviso per una dereferenza nulla, anche se tecnicamente si tratta di una condizione di gara TOCTOU. Ricordo che Mads Torgersen parlava di come lo consideravano, ma genererebbe così tanti falsi positivi che l'intera funzionalità dei tipi di riferimento nullable sarebbe effettivamente inutile: il 99% delle volte le tue proprietà non verranno modificate da un altro thread. Quindi tutto ciò che dovresti fare è creare un attributo che renderebbe il controllo su questa proprietà come un controllo per null su un'altra proprietà.
V0ldek,

2
Ho risolto il problema "Impossibile trovare una proposta per questo". ( github.com/dotnet/csharplang/issues/2997 ) Augurami buona fortuna.
John Melville,

-10

String è un tipo di riferimento e nullable (ad es. int?) È tipi di valore nullable. Quindi non puoi davvero farlo string? myString; Ciò di cui hai bisogno è questo:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.