Um tipo de referência não anulável no C # 8 pode ser nulo em tempo de execução?

10

Parece-me que realmente não há garantia de que uma variável não anulável nunca terá nulo. Imagine que eu tenho uma classe que possui uma propriedade que não é anulável:

public class Foo
{
    public Foo(string test)
    {
        Test = test;
    }
    public string Test {get;set;}
}

Agora, isso pode parecer que agora não pode ser nulo. Mas se fizermos referência a essa classe com outra biblioteca que não usa contexto nulo, nada impede que ele envie nulo lá.

Isso está correto ou há algumas verificações em tempo de execução, talvez, que garantam isso?

Ilya Chernomordik
fonte
É public void Foo(string test){...}ou public Foo(string test){...}?
HuMpty duMpty
Obrigado, eu consertei. Isso é o que acontece quando o homem confia muito em R # para gerar construtores :)
Ilya Chernomordik
2
O C # 9 (provavelmente) adicionará validação nula simplificada .
Steven
Em resumo, o recurso "tipos de referência anuláveis" está completamente quebrado.
Alejandro

Respostas:

9

É o que a MS diz sobre ( https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/upgrade-to-nullable-references#interfaces-with-external-code ):

O compilador não pode validar todas as chamadas para suas APIs públicas, mesmo que seu código seja compilado com os contextos de anotação anuláveis ​​ativados. Além disso, suas bibliotecas podem ser consumidas por projetos que ainda não optaram por usar tipos de referência anuláveis. Valide entradas para APIs públicas, mesmo que você as tenha declarado como tipos não anuláveis.

Dmitri Tsoy
fonte
2

alguém sempre pode fazer

var myFoo = new Foo(null);

Pode ser que você possa usar o Domain Driven Design

public class Foo
{
    public Foo(string test)
    {
         if (string.IsNullOrWhiteSpace(test))
             throw new ArgumentNullException(nameof(test));

         Test = test;
    }
    public string Test {get;private set;}
}
huMpty duMpty
fonte
sim, você está certo, é apenas um aviso de qualquer maneira, eu acho. Espero que, no futuro, eles possam realmente aplicá-lo de alguma maneira, como, por exemplo, em Kotlin
Ilya Chernomordik
2

Você está correto, outro código que não está usando o novo recurso pode atribuir nulo a essa propriedade; não há verificações em tempo de execução; são apenas dicas completas.

Você sempre pode fazer isso sozinho se quiser uma verificação de tempo de execução:

public string Test { get; set{ if (value == null) throw new ArgumentNullException() } }

Observe que você pode garantir que não seja nulo na maioria do seu código, basta adicionar guardas à API pública de nível superior e garantir que as classes sejam adequadamente seladas etc.

Claro que as pessoas ainda podem usar a reflexão para f *** seu código, mas então é sobre eles

Milney
fonte
Portanto, isso efetivamente significa que ainda posso obter uma exceção de referência nula, mesmo que eu use um tipo não nulo, certo?
Ilya Chernomordik
Bem ... você não pode no código que compila, porque você tem as dicas ... mas o código de outras pessoas que não têm dicas, mas faça referência ao seu código - sim, eles podem obter uma exceção nula
Milney
Bem, se, por exemplo, um AutoMapper usa seu construtor, ou algo parecido, ainda que você é quem terá a exceção :)
Ilya Chernomordik
Of course people can still use reflection to f*** your code up, verdadeiro, verdadeiro mesmo. Você definitivamente pode usar a reflexão para fazer isso, é recomendado , não , as pessoas ainda fazem isso, sim.
Çöđěxěŕ
2

Mesmo em seu próprio código, se você optar por fazê-lo, poderá passar nullusando o operador que perdoa nulo. null!é considerado não nulo no que diz respeito à análise de nulidade do compilador.

Damien_The_Unbeliever
fonte
-1

Para lidar com verificações nulas e também tornar seu código legível, sugiro o padrão Null Object Design.

Mais leitura aqui:

https://www.c-sharpcorner.com/article/null-object-design-pattern/

Basicamente, envolve a criação de um novo objeto derivado da mesma interface e com instância nula.

Exemplo:

public class NullExample : IExample  
{  
    private static NullExample _instance;  
    private NullExample()  
    { }  

    public static NullExample Instance  
    {  
        get {  
            if (_instance == null)  
                return new NullExample();  
            return _instance;  
        }  
    }  

    //do nothing methods  
    public void MethodImplementedByInterface1()  
    { }  

    public void MethodImplementedByInterface1()  
    { }  
}  

Os nulos não podem ser evitados, mas podem ser verificados de maneira limpa.

Gauravsa
fonte