Posso dizer às referências anuláveis ​​em C # que um método é efetivamente uma verificação nula em um campo


14

Considere o seguinte código:

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

No Name = Name.ToUpper (), recebo um aviso de que Name é uma possível referência nula, o que está claramente incorreto. Eu posso curar esse aviso inserindo HasName para que a condição seja if (Name! = Null).

Existe alguma maneira de instruir o compilador que uma resposta verdadeira de HasName implica uma restrição de não anulabilidade em Name?

Isso é importante porque o HasName pode realmente testar muito mais coisas, e eu posso querer usá-lo em vários locais, ou pode ser uma parte pública da superfície da API. Há muitas razões para querer incluir o cheque nulo em seu próprio método, mas fazer isso parece interromper o verificador de referência anulável.


11
IMO você deve usar HasValueem um tipo anulável, não compará-lo null. Provavelmente não afeta o seu problema.
Fredrik

Penso que, para o seu caso, você pode agrupar seu código #nullable disableposteriormente #nullable enableou restorenovamente ( docs.microsoft.com/en-us/dotnet/csharp/… ).
GaryNg

5
você pode usar o !operador "dammit" . if(HasName) { Name = Name!.ToUpper(); }
Jan Paolo Go

11
para um aplicativo multithread, você pode fazer com que Name seja nulo após a verificação de HasName, usar a variável localmente em vez de voltar para a propriedade (quem sabe o que a propriedade pode fazer em seu getter) causará alguns erros estranhos (lembre-se o uso de um manipulador de eventos em que isso aconteceu um monte)
XIU

Respostas:


3

Olhei em volta para os diferentes atributos System.Diagnostics.CodeAnalysise não consegui encontrar nada aplicável, o que é muito decepcionante. O mais próximo possível do que você deseja parece ser:

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

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

Parece bem complicado, eu sei. Você pode procurar nos documentos do MSDN atributos anuláveis , talvez encontre algo mais arrumado.


2
Parece que precisamos de mais atributos ou algo como afirmações de texto dactilografado
Stilgar

Vou escolher esta como a resposta, porque parece que a resposta real, como eu temia, é "não, o c # ainda não faz isso".
John Melville

@JohnMelville Também não consegui encontrar uma proposta para esse recurso, então acho que não podemos esperar que isso mude tão cedo.
V0ldek

2
@XIU O compilador já é relaxado nesse aspecto. Se você o fizer if(Name != null) return Null.ToUpper(), não haverá aviso para uma desreferência nula, embora tecnicamente seja uma condição de corrida TOCTOU. Lembro-me de Mads Torgersen falando sobre como eles consideraram isso, mas geraria tantos falsos positivos que todo o recurso de tipos de referência nulizáveis ​​seria efetivamente inútil - 99% do tempo em que suas propriedades não serão alteradas por outro segmento. Portanto, tudo que você precisa fazer é criar um atributo que faça com que a verificação nesta propriedade seja tratada como uma verificação de nulo em outra propriedade.
V0ldek

2
Corrigi o problema "não consigo encontrar uma proposta para este". ( github.com/dotnet/csharplang/issues/2997 ) Deseje-me sorte.
John Melville

-10

String é um tipo de referência e anulável (por exemplo int?) são tipos de valores anuláveis. Então você não pode realmente fazer isso string? myString; O que você precisa é este:

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.