Aktualizacja: Począwszy od programu Visual Studio 2015, kompilator C # (wersja językowa 6) rozpoznaje teraz ?.
operatora, dzięki czemu „głębokie sprawdzanie wartości null” jest dziecinnie proste. Zobacz tę odpowiedź, aby uzyskać szczegółowe informacje.
Oprócz przeprojektowania kodu, jak
sugerowała ta usunięta odpowiedź , inną (choć okropną) opcją byłoby użycie try…catch
bloku, aby sprawdzić, czy NullReferenceException
wystąpi jakiś czas podczas tego głębokiego wyszukiwania właściwości.
try
{
var x = cake.frosting.berries.loader;
...
}
catch (NullReferenceException ex)
{
...
}
Osobiście nie zrobiłbym tego z następujących powodów:
- Nie wygląda to ładnie.
- Używa obsługi wyjątków, która powinna być ukierunkowana na wyjątkowe sytuacje, a nie coś, czego można się spodziewać często podczas normalnego przebiegu operacji.
NullReferenceException
s prawdopodobnie nigdy nie powinny być wyraźnie przechwytywane. (Zobacz to pytanie .)
Czy jest więc możliwe użycie jakiejś metody rozszerzenia, czy też byłaby to funkcja języka, [...]
Prawie na pewno musiałaby to być funkcja języka (która jest dostępna w C # 6 w postaci .?
i?[]
operatorów ), chyba że C # ma już bardziej wyrafinowaną leniwą ocenę lub jeśli nie chcesz użyć odbicia (co prawdopodobnie również nie jest dobry pomysł ze względu na wydajność i bezpieczeństwo typu).
Ponieważ nie ma sposobu, aby po prostu przekazać cake.frosting.berries.loader
do funkcji (zostanie ona oceniona i zgłosi zerowy wyjątek odniesienia), musiałbyś zaimplementować ogólną metodę wyszukiwania w następujący sposób: Pobiera obiekty i nazwy właściwości do sprawdzać:
static object LookupProperty( object startingPoint, params string[] lookupChain )
{
}
...
var x = LookupProperty( cake, "frosting", "berries", "loader" );
(Uwaga: edytowano kod).
Szybko widzisz kilka problemów z takim podejściem. Po pierwsze, nie uzyskujesz żadnego bezpieczeństwa typu i możliwego pakowania wartości właściwości prostego typu. Po drugie, możesz albo powrócić, null
jeśli coś pójdzie nie tak i będziesz musiał sprawdzić to w swojej funkcji wywołującej, albo zgłosisz wyjątek i wrócisz do miejsca, w którym zacząłeś. Po trzecie, może być powolne. Po czwarte, wygląda brzydiej niż to, od czego zacząłeś.
[...], czy to po prostu zły pomysł?
Zostałbym z:
if (cake != null && cake.frosting != null && ...) ...
lub skorzystaj z powyższej odpowiedzi Mehrdada Afshariego.
PS: Kiedy pisałem tę odpowiedź, oczywiście nie brałem pod uwagę drzew wyrażeń dla funkcji lambda; zobacz np. odpowiedź @driis, aby znaleźć rozwiązanie w tym kierunku. Opiera się również na pewnego rodzaju refleksji i dlatego może nie działać tak dobrze, jak prostsze rozwiązanie ( if (… != null & … != null) …
), ale może być lepiej ocenione z punktu widzenia składni.