Zine.net online

Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc
w Szukaj

arkadiusz.wasniewski

ReSharper ostrzega - Possible NullReferenceException

Kontekst rozważań jest następujący. Metoda (wersja uproszczona poniżej) buduje ściśle określoną sekwencję sterującą. Dokumentacja mówi, iż sekwencja ta musi zawierać dokładnie osiem parametrów oddzielonych średnikiem. Dopuszcza się przy tym parametry puste. Użytkownik nie jest karany (np. wyjątek) za brak parametrów. Nie spotka go też przykra niespodzianka, jeśli poda zbyt dużo parametrów.

    1     public void SampleReport(string[] names)

    2     {

    3         const byte maxNumberOfNames = 8;

    4 

    5         int numberOfNames = names == null ? 0 : names.Length;

    6 

    7         byte[] sequence;

    8 

    9         using (SequenceBuilder builder = new SequenceBuilder())

   10         {

   11             for (int i = 0; i < maxNumberOfNames; i++)

   12             {

   13                 if (i < numberOfNames)

   14                 {

   15                     builder.AppendParameter(names[i]);

   16                 }

   17                 builder.AppendSemicolon();

   18             }

   19 

   20             sequence = builder.BuildUp();

   21         }

   22 

   23         printController.Print(sequence);

   24     }

Pewnym zdziwieniem w związku z tym było dla mnie zgłoszenie przez ReSharper ostrzeżenia Possible 'System.NullReferenceException' dla linii numer 15. Wśród sugerowanych akcji zaś pojawiła się propozycja sprawdzenia czy parametr names nie jest null. W pierwszej chwili podpowiedź ta zaskoczyła mnie. Kod jest poprawny. Po dłuższym zastanowieniu stwierdziłem, iż ostrzeżenie programu ReSharper ma sens. To, że parametr names w tym miejscu programu nigdy nie będzie miał wartości null jest w teraz oczywiste. Za kilka miesięcy zaś może już tak nie być. Zamiast analizować kod można przecież wprost powiedzieć, iż w tym miejscu nie ma prawa nie być wartości. Jak to osiągnąć? Oczywiście poprzez zastosowanie asercji, które powinny być wykorzystywane do informowania siebie samego i innych programistów pracujących nad kodem, iż w danym konkretnym miejscu oczekujemy takich a nie innych wartości. Po wstawieniu właściwego sprawdzenia (linia numer 15) ReSharper usunął wcześniejsze zastrzeżenia.

    1     public void SampleReport(string[] names)

    2     {

    3         const byte maxNumberOfNames = 8;

    4 

    5         int numberOfNames = names == null ? 0 : names.Length;

    6 

    7         byte[] sequence;

    8 

    9         using (SequenceBuilder builder = new SequenceBuilder())

   10         {

   11             for (int i = 0; i < maxNumberOfNames; i++)

   12             {

   13                 if (i < numberOfNames)

   14                 {

   15                     Debug.Assert(names != null);

   16                     builder.AppendParameter(names[i]);

   17                 }

   18                 builder.AppendSemicolon();

   19             }

   20 

   21             sequence = builder.BuildUp();

   22         }

   23 

   24         printController.Print(sequence);

   25     }

Asercja sprawdzana jest tylko w trybie Debug. W trybie Release pojawianie się takich okien jest w moim mniemaniu niedopuszczalne.

Opublikowane 9 stycznia 2008 23:15 przez arkadiusz.wasniewski

Komentarze:

 

Marcin Hoppe said:

Przyznam się, że nie do końca rozumiem: skoro ReSharper ostrzega, że wartość wyrażenia names[i] może być równa null, to asercja powinna sprawdzać właśnie to: Debug.Assert(names[i] != null). Moja druga koncepcja jest taka, że miałeś na myśli to, że wartość parametru names jest równa null i w związku z tym wartość wyrażenia names[i] będzie rzucała wyjątek NullReferenceException. W tej chwili przed takim wyjątkiem chroni konstrukcja programu (wartość zmiennej numberOfNames). Mógłbyś trochę rozjaśnić?

stycznia 10, 2008 09:06
 

Marcin Hoppe said:

Mała korekta: oczywiście to nie wyrażenie rzuca wyjątek, ale próba obliczenia wartości tego wyrażenia. Tak dla ścisłości :).

stycznia 10, 2008 09:18
 

arkadiusz.wasniewski said:

Dzięki Marcinie za uważne czytanie i uwagi. Oczywiście masz rację. W tekście popełniłem błąd (już poprawiłem). ReSharper mówił o names a nie names[i]. Jeszcze raz dzięki za uwagi. Pozdrawiam.

Arek

stycznia 10, 2008 09:43
 

arkadiusz.wasniewski said:

Kilka miesięcy temu stałem się szczęśliwym posiadaczem projektu na przygotowanie kompletnego rozwiązania

grudnia 11, 2008 12:45
Komentarze anonimowe wyłączone
W oparciu o Community Server (Personal Edition), Telligent Systems