Czy w środowisku wykonawczym typ odwołania nie dopuszczający wartości zerowej w C # 8 może mieć wartość NULL?

10

Wydaje mi się, że tak naprawdę nie ma gwarancji, że zmienna nie dopuszczająca wartości zerowej nigdy nie będzie miała wartości null. Wyobraź sobie, że mam klasę, która ma jedną właściwość, która nie ma wartości zerowej:

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

Teraz może się wydawać, że teraz nie może być zerowy. Ale jeśli odniesiemy tę klasę do innej biblioteki, która nie korzysta z kontekstu zerowalnego, nic nie powstrzyma jej przed wysłaniem wartości null.

Czy to jest poprawne, czy są też jakieś kontrole środowiska wykonawczego, które mogą to zapewnić?

Ilya Chernomordik
źródło
Czy to public void Foo(string test){...}czy public Foo(string test){...}?
huMpty duMpty
Dzięki, naprawiłem to. Tak się dzieje, gdy człowiek za bardzo polega na R #, aby generować konstruktory :)
Ilya Chernomordik
2
C # 9 (prawdopodobnie) doda uproszczoną weryfikację zerową .
Steven
Krótko mówiąc, funkcja „zerowalnych typów referencyjnych” jest całkowicie zepsuta.
Alejandro

Odpowiedzi:

9

O tym mówi MS ( https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/upgrade-to-nullable-references#interfaces-with-external-code ):

Kompilator nie może zweryfikować wszystkich wywołań publicznych interfejsów API, nawet jeśli kod jest skompilowany z włączonymi kontekstami adnotacji z dopuszczaniem wartości zerowych. Co więcej, biblioteki mogą być wykorzystywane przez projekty, które jeszcze nie zdecydowały się na użycie zerowych typów referencji. Sprawdź poprawność danych wejściowych do publicznych interfejsów API, mimo że zadeklarowałeś je jako typy, które nie mają wartości NULL.

Dmitri Tsoy
źródło
2

ktoś zawsze może to zrobić

var myFoo = new Foo(null);

Możliwe, że możesz użyć 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
źródło
tak, masz rację, to chyba ostrzeżenie. Mam nadzieję, że w przyszłości naprawdę mogą to egzekwować, jak np. Kotlin
Ilya Chernomordik
2

Masz rację, inny kod, który nie korzysta z nowej funkcji, może przypisać null tej właściwości, nie ma żadnych kontroli w czasie wykonywania, to tylko wskazówki dotyczące zgodności.

Zawsze możesz to zrobić samodzielnie, jeśli chcesz sprawdzić środowisko wykonawcze:

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

Pamiętaj, że możesz zagwarantować, że nie będziesz mieć wartości zerowej w większości swojego kodu, wystarczy dodać zabezpieczenia do publicznego interfejsu API najwyższego poziomu i upewnić się, że klasy są odpowiednio zapieczętowane itp.

Oczywiście ludzie nadal mogą używać refleksji, aby sfałszować twój kod, ale potem jest on na nich

Milney
źródło
Oznacza to więc, że nadal mogę uzyskać wyjątek Null Reference, nawet jeśli używam typu, który nie ma wartości null, prawda?
Ilya Chernomordik,
Cóż ... nie możesz w kompilowanym kodzie, bo masz wskazówki ... ale kod innych ludzi, które nie mają podpowiedzi, ale odwołaj się do kodu - tak, mogą otrzymać wyjątek zerowy
Milney
Cóż, jeśli np. Automapper używa twojego konstruktora, czy coś w tym rodzaju, nadal to Ty dostaniesz wyjątek :)
Ilya Chernomordik
Of course people can still use reflection to f*** your code up, prawda, prawda naprawdę. Zdecydowanie możesz użyć do tego refleksji, czy jest to zalecane , nie , czy ludzie nadal to robią, tak.
Çöđěxěŕ
2

Nawet we własnym kodzie, jeśli zdecydujesz się to zrobić, możesz przekazać null, korzystając z operatora zerującego. null!jest uważany za wartość zerową, jeśli chodzi o analizę podatności kompilatora.

Damien_The_Unbeliever
źródło
-1

Aby poradzić sobie z zerowymi kontrolami i uczynić kod czytelnym, sugeruję wzorzec Null Object Design.

Więcej informacji tutaj:

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

Zasadniczo polega na utworzeniu nowego obiektu, który pochodzi z tego samego interfejsu i ma instancję zerową.

Przykład:

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

Wartości zerowych nie da się uniknąć, jednak można je dokładnie sprawdzić.

Gauravsa
źródło