Jaki wyjątek rzucać gdy mamy nieobsłużonego enuma

Gdy sterujemy przepływem sterowania za pomocą switcha i tym co sprawdzamy jest enum to warto obsłużyć też przypadek default. Czyli co stanie się gdy enum ma wartość spoza tych wymienionych w case‚ach. Warto wtedy rzucić wyjątek.

Taki kod wygeneruje nam ReSharper (i jest to niezły kod):

void Execute(DocumentStatus documentStatus)
{
    switch (documentStatus)
    {
        case DocumentStatus.Draft:
            // Do sth
            break;
        case DocumentStatus.Released:
            // Do sth
            break;
        default:
            throw new ArgumentOutOfRangeException(nameof(documentStatus), documentStatus, null);
    }
}

Dlaczego jest to ważne? Poniższy kod zarówno się skompiluje jak i wykona poprawnie w runtime, mimo że żadna z wartości nie przyjmuje 111:

DocumentStatus AssignInvalidValue()
{
    return (DocumentStatus) 111;
}

Więcej w Rzutowanie na Enum z niepewnego źródła

Błąd, który dotychczas robiłem to wypełniałem 3-ci argument w konstruktorze klasy ArgumentOutOfRangeException. Pisałem tam coś w stylu:

throw new ArgumentOutOfRangeException(nameof(documentStatus), documentStatus,
    $"Enum '{documentStatus.GetType().Name}' has invalid value '{documentStatus}'");

Dzięki czemu przechwycony wyjątek wyglądał tak:

enum exception

Jest to dla tego przepadku zupełnie zbędne. Gdy przekażemy tam nulla to przechwycony wyjątek będzie wyglądał tak:

enum exception without message

A mając stack trace zobaczymy gdzie co i jak się podziało.

Metoda fabrykująca takie wyjątki

Jednak najlepszym sposobem jest jednak opakowanie tworzenia tego wyjątku. Dla mnie też kiedyś dziwne było żeby zwracać z funkcji wyjątek który dopiero później będzie rzucany. Przekonałem się jednak, że to dobra praktyka, takie scentralizowane tworzenie np message dla wyjątku. Np taka klasa:

public static ArgumentOutOfRangeException CreateMissingEnumException<T>(string paramName, T value)
    where T : struct 
{
    return new ArgumentOutOfRangeException(paramName, value,
        $"Enum '{value.GetType().Name}' has invalid value '{value}'");
}

i wywołanie oraz podgląd przechwyconego wyjątku:

enum create missing enum exception

Advertisements
Ten wpis został opublikowany w kategorii Programowanie i oznaczony tagami , , . Dodaj zakładkę do bezpośredniego odnośnika.

2 odpowiedzi na „Jaki wyjątek rzucać gdy mamy nieobsłużonego enuma

  1. „Dla mnie też kiedyś dziwne było żeby zwracać z funkcji wyjątek który dopiero później będzie rzucany. Przekonałem się jednak, że to dobra praktyka,” – czy mógłbyś coś więcej powiedzieć – dlaczego to dobra praktyka i jak się o tym przekonałeś?

    • Jeśli w 4 miejscach w klasie rzucasz taki sam wyjątek, który ma taki sam message i ustawia taki sam parametr (już zależny od kontekstu) to stosujesz zwykłą zasadę DRY (Don’t Repeat Yourself).

      Wtedy naturalnie dojdziesz do wywoływania:
      throw BuildCommunicationException(connectionId);

      i bez żadnego patosu nawet nie wiedząc o tym zastosowałeś wzorzec budowniczy (builder).
      A czasem do zbudowania wyjątku potrzebna jest logika z if’ami i tym bardziej naturalna i rozbudowana będzie taka fabryka

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s