Há um padrão nas classes C # exemplificadas por Dictionary.TryGetValue
e int.TryParse
: um método que retorna um valor booleano indicando o sucesso de uma operação e um parâmetro out contendo o resultado real; se a operação falhar, o parâmetro out será definido como nulo.
Vamos supor que estou usando referências não anuláveis em C # 8 e quero escrever um método TryParse para minha própria classe. A assinatura correta é esta:
public static bool TryParse(string s, out MyClass? result);
Como o resultado é nulo no caso falso, a variável out deve ser marcada como anulável.
No entanto, o padrão Try é geralmente usado assim:
if (MyClass.TryParse(s, out var result))
{
// use result here
}
Como apenas insiro a ramificação quando a operação é bem-sucedida, o resultado nunca deve ser nulo nessa ramificação. Mas como o marquei como nulo, agora tenho que verificar isso ou usar !
para substituir:
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
}
Isso é feio e um pouco anti-econômico.
Por causa do padrão de uso típico, tenho outra opção: mentir sobre o tipo de resultado:
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;
}
Agora, o uso típico se torna melhor:
if (MyClass.TryParse(s, out var result))
{
Console.WriteLine("Look: {0}", result.SomeProperty); // no warning
}
mas o uso atípico não recebe o aviso que deveria:
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.
}
Agora não tenho certeza de qual caminho seguir aqui. Existe uma recomendação oficial da equipe de idiomas C #? Existe algum código CoreFX já convertido em referências não anuláveis que possa me mostrar como fazer isso? ( Procurei TryParse
métodos. IPAddress
É uma classe que possui uma, mas não foi convertida na ramificação principal do corefx.)
E como código genérico como Dictionary.TryGetValue
lida com isso? (Possivelmente com um MaybeNull
atributo especial do que encontrei.) O que acontece quando instanciamos um Dictionary
com um tipo de valor não nulo?
MyClass?
) e faça uma troca com aecase MyClass myObj:
(opcional)case null:
.