Esiste un modello nelle classi C # esemplificato da Dictionary.TryGetValuee int.TryParse: un metodo che restituisce un valore booleano che indica il successo di un'operazione e un parametro out contenente il risultato effettivo; se l'operazione non riesce, il parametro out è impostato su null.
Supponiamo che io stia usando riferimenti non annullabili C # 8 e voglia scrivere un metodo TryParse per la mia classe. La firma corretta è questa:
public static bool TryParse(string s, out MyClass? result);
Poiché il risultato è nullo nel caso falso, la variabile out deve essere contrassegnata come nullable.
Tuttavia, il modello Try viene generalmente utilizzato in questo modo:
if (MyClass.TryParse(s, out var result))
{
// use result here
}
Poiché inserisco il ramo solo quando l'operazione ha esito positivo, il risultato non dovrebbe mai essere nullo in quel ramo. Ma poiché l'ho contrassegnato come nullable, ora devo verificarlo o utilizzare !per sovrascrivere:
if (MyClass.TryParse(s, out var result))
{
Console.WriteLine("Look: {0}", result.SomeProperty); // compiler warning, could be null
Console.WriteLine("Look: {0}", result!.SomeProperty); // need override
}
Questo è brutto e un po 'non ergonomico.
A causa del tipico modello di utilizzo, ho un'altra opzione: mentire sul tipo di risultato:
public static bool TryParse(string s, out MyClass result) // not nullable
{
// Happy path sets result to non-null and returns true.
// Error path does this:
result = null!; // override compiler complaint
return false;
}
Ora l'uso tipico diventa più bello:
if (MyClass.TryParse(s, out var result))
{
Console.WriteLine("Look: {0}", result.SomeProperty); // no warning
}
ma l'uso atipico non riceve l'avviso che dovrebbe:
else
{
Console.WriteLine("Fail: {0}", result.SomeProperty);
// Yes, result is in scope here. No, it will never be non-null.
// Yes, it will throw. No, the compiler won't warn about it.
}
Ora non sono sicuro su quale strada andare qui. Esiste una raccomandazione ufficiale del team linguistico C #? Esiste già un codice CoreFX già convertito in riferimenti non annullabili che potrebbe mostrarmi come fare? (Sono andato alla ricerca di TryParsemetodi. IPAddressÈ una classe che ne ha una, ma non è stata convertita nel ramo principale di corefx.)
E come fa il codice generico a Dictionary.TryGetValuegestire questo? (Forse con un MaybeNullattributo speciale da quello che ho trovato.) Cosa succede quando ho un'istanza di un Dictionarytipo di valore non annullabile?
MyClass?), e fai un interruttore su di esso con uncase MyClass myObj:e (un'opzione)case null:.