Typ odwołania zerowalnego w C # 8, gdy używasz klas DTO z ORM

9

Aktywowałem tę funkcję w projekcie posiadającym klasy obiektów przesyłania danych (DTO), jak podano poniżej:

public class Connection
    {
        public string ServiceUrl { get; set; }
        public string? UserName { get; set; }
        public string? Password { get; set; }
        //... others 
    }

Ale dostaję błąd:

CS8618: Właściwość niezerowa „ServiceUrl” jest niezainicjowana. Rozważ zadeklarowanie właściwości jako zerowalną.

To jest klasa DTO, więc nie inicjuję właściwości. Będzie to odpowiedzialnością kodu inicjującego klasę, aby upewnić się, że właściwości nie mają wartości null.

Na przykład osoba dzwoniąca może:

var connection = new Connection
{
  ServiceUrl=some_value,
  //...
}

Moje pytanie: Jak radzić sobie z takimi błędami w klasach DTO, gdy włączony jest kontekst dopuszczalności C # 8?

M.Hassan
źródło
3
Podczas inicjowania konstrukcji w sposób pokazany na ekranie uruchamia się domyślny konstruktor (inicjowanie ServiceUrl do wartości domyślnej (która dla łańcuchów ma wartość null)). Następnie uruchamia się instrukcja initialize. Jeśli chcesz, aby nie była zerowalna, musi wyjść ze wszystkich zainicjowanych konstruktorów
Flydog57
POCO nie oznacza, że ​​nie ma konstruktora ani że właściwości nie są inicjowane. Oznacza to Plain Old C# Object. Po prostu obiekt jak każdy inny, bez dziedziczenia po specjalnej klasie. Podejrzewam, że masz inne pytanie. Jak tworzyć DTO -Data Transfer Objects
Panagiotis Kanavos,
This should be the responsibility of the one initializing the class to ensure that the properties are non-nullklasa powinna być zawsze w poprawnym stanie. Jeśli nullnie jest dozwolone, właściwość nigdy nie powinna być pusta. Być może zamiast podstawowego ciągu znaków powinieneś użyć specjalnej klasy dla adresu URL, która może mieć wartość lub None`Missing`, jak klasa Option w F #. C # 8 pozwala pisać takie klasy i sprawdzać je za pomocą dopasowania wzorca
Panagiotis Kanavos
@Panagiotis Kanavos, Klasa, w moim przypadku, ma ograniczenie do konstruktora bez parametrów. Więc muszę używać właściwości initializer: public string ServiceUrl { get; set; } = default! ;. Mam nadzieję, że Roslyn może mieć w przyszłości sposób obsługi późnej inicjalizacji poza zakresem ctor. Używałem MayBe <T> (podobnie jak klasa Option), ale dla nowego kodu przestawiłem się na zerowy typ referencyjny w c # 8.
M.Hassan,
NRTs nie są Maybes w rzeczywistości Maybes są teraz jeszcze bardziej ważne i łatwiejsze w użyciu. Oczywiście pod warunkiem, że są budowane przy użyciu idiomów C #, które ułatwiają pracę z dopasowywaniem wzorców
Panagiotis Kanavos

Odpowiedzi:

9

Kolejne rozwiązanie jest zalecane przez EF Core i EF6 patrz

1) Poprzez zainicjowanie za null!pomocą wybaczającego operatora

public string ServiceUrl { get; set; } = null! ;
//or
public string ServiceUrl { get; set; } = default! ;

2) Za pomocą pola podkładowego:

        private string _ServiceUrl;
        public string ServiceUrl
        {
            set => _ServiceUrl = value;
            get => _ServiceUrl
                   ?? throw new InvalidOperationException("Uninitialized property: " + nameof(ServiceUrl));
        }

M.Hassan
źródło
Pytanie wspomniało, że nie może korzystać z !operatora.
Athanasios Kataras
Nie mogę użyć! z typem, ale link, o którym wspomniałem, pokazuje, jak zainicjować za pomocą null !. To rozwiązanie obejścia. Zmodyfikowałem pytanie.
M.Hassan
8

Jeśli nie ma wartości zerowej, co może zrobić kompilator po zainicjowaniu obiektu?

Domyślna wartość łańcucha to null, więc będziesz

  1. albo trzeba przypisać domyślną wartość ciągu do deklaracji

    public string ServiceUrl { get; set; } = String.Empty;

  2. Lub zainicjuj wartość w domyślnym konstruktorze, aby pozbyć się ostrzeżenia

  3. Użyj !operatora (którego nie możesz użyć)

  4. Uczyń go zerowalnym, jak wspomniał Robbpriestley.

Athanasios Kataras
źródło
4
Lub dodaj konstruktor, który akceptuje adres URL usługi jako ciąg niedopuszczalny, oczywiście.
Jon Skeet
ServiceUrl'nie może być = String.Empty. Istnieją inne właściwości typu złożonego, które nie mogą mieć wartości NULL, więc użyłem default: „public MyClass MyProperty {get; zestaw; } = domyślnie! „aby zatrzymać ostrzeżenie. Ta klasa (i inne) jest konstruktorem bez parametrów i została ostatnio zainicjowana poza zakresem ctor.
M.Hassan
0

Kolejna rzecz, która może się przydać w niektórych scenariuszach:

[SuppressMessage("Compiler", "CS8618")]

Może być stosowany na elemencie członkowskim lub całym typie.


Jeszcze inną rzeczą do rozważenia jest dodanie #nullable disablena wierzchu pliku, aby wyłączyć odwołanie zerowalne dla całego pliku.

Shimmy Weitzhandler
źródło