Obecnie piszę kod dla UnconstrainedMelody, który ma ogólne metody do wyliczenia.
Teraz mam statycznych klasy z grupą metod, które są wyłącznie przeznaczone do pracy z „flagi” teksty stałe. Nie mogę dodać tego jako ograniczenia ... więc możliwe, że będą wywoływane także z innymi typami wyliczeń. W takim przypadku chciałbym zgłosić wyjątek, ale nie jestem pewien, który z nich rzucić.
Żeby zrobić ten konkret, jeśli mam coś takiego:
// Returns a value with all bits set by any values
public static T GetBitMask<T>() where T : struct, IEnumConstraint
{
if (!IsFlags<T>()) // This method doesn't throw
{
throw new ???
}
// Normal work here
}
Jaki jest najlepszy wyjątek do rzucenia? ArgumentException
brzmi logicznie, ale jest to raczej argument typu niż normalny argument, który może łatwo zmylić sprawę . Czy powinienem przedstawić własną TypeArgumentException
klasę? Użyj InvalidOperationException
? NotSupportedException
? Coś jeszcze?
Bym raczej nie tworzyć własne wyjątek dla tego chyba że jest to wyraźnie, co trzeba zrobić.
Odpowiedzi:
NotSupportedException
wygląda na to, że po prostu pasuje, ale dokumentacja wyraźnie stwierdza, że powinien być używany w innym celu. Z uwag klasy MSDN:Oczywiście istnieje sposób, który
NotSupportedException
jest oczywiście wystarczająco dobry, zwłaszcza biorąc pod uwagę jego zdroworozsądkowe znaczenie. Powiedziawszy to, nie jestem pewien, czy to w porządku.Biorąc pod uwagę cel Unconstrained Melody ...
... wydaje się,
Exception
że nowy może być w porządku, pomimo dużego ciężaru dowodu, który słusznie musimy spełnić przed stworzeniem niestandardowegoExceptions
. Coś takiegoInvalidTypeParameterException
może być przydatne w całej bibliotece (a może nie - to z pewnością przypadek skrajny, prawda?).Czy klienci będą musieli umieć odróżnić to od wyjątków BCL? Kiedy klient może przypadkowo nazwać to, używając wanilii
enum
? Jak odpowiedziałbyś na pytania postawione przez zaakceptowaną odpowiedź na jakie czynniki należy wziąć pod uwagę podczas pisania niestandardowej klasy wyjątków?źródło
InvalidOperationException
Takie rzeczy są okropne, ponieważ „Foo prosi Collection Bar o dodanie czegoś, co już istnieje, więc Bar rzuca IOE” i „Foo prosi Collection Bar o dodanie czegoś, więc Bar wywołuje Boz, który wyrzuca IOE, mimo że Bar tego nie oczekuje” oba wyrzucą ten sam typ wyjątku; kod, który spodziewa się złapać pierwszy, nie będzie oczekiwał drugiego. Powiedziawszy to ...Foo<T>
za „typ ogólny” iFoo<Bar>
za „typ szczególny” w tym kontekście, mimo że nie ma między nimi relacji „dziedziczenia”.Unikałbym NotSupportedException. Ten wyjątek jest używany w ramach, w którym metoda nie jest zaimplementowana i istnieje właściwość wskazująca, że ten typ operacji nie jest obsługiwany. Nie pasuje tutaj
Myślę, że InvalidOperationException to najbardziej odpowiedni wyjątek, jaki można tutaj rzucić.
źródło
T
jestenum
ozdobionyFlags
, byłoby ważne, aby rzucić NSE.StupidClrException
to zabawne imię;)Programowanie ogólne nie powinno generować w czasie wykonywania nieprawidłowych parametrów typu. Nie powinien się kompilować, powinieneś mieć wymuszenie czasu kompilacji. Nie wiem, co
IsFlag<T>()
zawiera, ale być może możesz to zmienić w wymuszanie czasu kompilacji, na przykład próbując stworzyć typ, który można utworzyć tylko za pomocą „flag”. Możetraits
klasa może pomóc.Aktualizacja
Jeśli musisz rzucić, zagłosowałbym na InvalidOperationException. Rozumowanie jest takie, że typy ogólne mają parametry, a błędy związane z parametrami (metody) są wyśrodkowane wokół hierarchii ArgumentException. Jednak zalecenie dotyczące ArgumentException stwierdza, że
Jest co najmniej jeden skok wiary w to, że zalecenia dotyczące parametrów metod mają być również stosowane do parametrów ogólnych , ale nie ma nic lepszego w SystemException hierachy imho.
źródło
IsFlag<T>
określa, czy wyliczenie zostało[FlagsAttribute]
zastosowane do niego, a środowisko CLR nie ma ograniczeń opartych na atrybutach. Byłoby to w idealnym świecie - albo byłby inny sposób, aby to ograniczyć - ale w tym przypadku to po prostu nie działa :(Użyłbym NotSupportedException, ponieważ to właśnie mówisz. Inne wyliczenia niż określone nie są obsługiwane . Oczywiście byłoby to wyraźniej określone w komunikacie o wyjątku.
źródło
Poszedłbym z
NotSupportedException
. ChoćArgumentException
wygląda dobrze, to naprawdę spodziewać po argument przekazywany do metody jest nie do przyjęcia. Argument typu jest cechą definiującą rzeczywistą metodę, którą chcesz wywołać, a nie prawdziwym „argumentem”.InvalidOperationException
powinno być wyrzucane, gdy wykonywana operacja może być prawidłowa w niektórych przypadkach, ale w konkretnej sytuacji jest to niedopuszczalne.NotSupportedException
jest generowany, gdy operacja jest z natury nieobsługiwana. Na przykład podczas implementowania interfejsu, w którym określony element członkowski nie ma sensu dla klasy. To wygląda na podobną sytuację.źródło
Najwyraźniej firma Microsoft używa
ArgumentException
do tego celu, jak pokazano na przykładzie Expression.Lambda <> , Enum.TryParse <> lub Marshal.GetDelegateForFunctionPointer <> w sekcji Wyjątki. Nie mogłem znaleźć żadnego przykładu wskazującego inaczej (pomimo wyszukiwania lokalnego źródła odniesienia dlaTDelegate
iTEnum
).Myślę więc, że można bezpiecznie założyć, że przynajmniej w kodzie firmy Microsoft powszechną praktyką jest stosowanie
ArgumentException
nieprawidłowych argumentów typu ogólnego oprócz podstawowych zmiennych. Biorąc pod uwagę, że opis wyjątków w dokumentach nie rozróżnia tych wyjątków , nie jest to również zbyt trudne.Miejmy nadzieję, że raz na zawsze zadecyduje o wszystkim.
źródło
TypeArgumentException
z tegoArgumentException
, po prostu dlatego, że argument typu nie jest regularny argument.Idę z NotSupportedExpcetion.
źródło
Zgłaszanie niestandardowego wyjątku powinno być zawsze wykonywane w każdym przypadku, gdy jest to wątpliwe. Wyjątek niestandardowy zawsze będzie działał, niezależnie od potrzeb użytkowników interfejsu API. Deweloper może złapać dowolny typ wyjątku, jeśli go to nie obchodzi, ale jeśli programista wymaga specjalnej obsługi, będzie SOL.
źródło
Co powiesz na dziedziczenie po NotSupportedException. Chociaż zgadzam się z @Mehrdad, że ma to największy sens, słyszę twój punkt widzenia, że nie wydaje się pasować idealnie. Więc dziedzicz po NotSupportedException, dzięki czemu ludzie kodujący w Twoim interfejsie API mogą nadal przechwytywać NotSupportedException.
źródło
Zawsze uważam na pisanie niestandardowych wyjątków, wyłącznie z tego powodu, że nie zawsze są one jasno udokumentowane i powodują zamieszanie, jeśli nie zostaną poprawnie nazwane.
W tym przypadku zgłosiłbym ArgumentException dla niepowodzenia sprawdzania flag. Tak naprawdę wszystko zależy od preferencji. Niektóre standardy kodowania, które widziałem, posunęły się nawet do określenia, które typy wyjątków powinny być stosowane w takich scenariuszach.
Jeśli użytkownik próbował przekazać coś, co nie było wyliczeniem, zgłosiłbym InvalidOperationException.
Edytować:
Inni podnoszą interesującą kwestię, że nie jest to obsługiwane. Moim jedynym zmartwieniem związanym z NotSupportedException jest to, że generalnie są to wyjątki, które są wyrzucane po wprowadzeniu do systemu „ciemnej materii” lub, mówiąc inaczej, „Ta metoda musi zostać wprowadzona do systemu w tym interfejsie, ale wygraliśmy nie włączaj go do wersji 2.4 "
Widziałem również NotSupportedExceptions jako wyjątek licencyjny „korzystasz z darmowej wersji tego oprogramowania, ta funkcja nie jest obsługiwana”.
Edycja 2:
Inny możliwy:
Wyjątek zgłoszony podczas używania nieprawidłowych argumentów, które są modułami wyliczającymi.
źródło
LicensingException
klasy dziedziczącej poInvalidOperationException
.Głosowałbym również na InvalidOperationException. Zrobiłem (niekompletny) schemat blokowy dotyczący wytycznych dotyczących rzucania wyjątków .NET w oparciu o wytyczne dotyczące projektowania ram, wyd. jakiś czas temu, jeśli ktoś jest zainteresowany.
źródło