Prozkoumání postupu při vytváření a vyvolání výjimek v jazyce C#
- 16 min
.NET poskytuje hierarchii tříd výjimek, které jsou odvozeny od System.Exception základní třídy. Aplikace jazyka C# mohou vytvářet a vyvolat výjimky libovolného typu výjimky. Vývojáři mohou také přizpůsobit objekty výjimek s informacemi o konkrétních aplikacích přiřazením hodnot vlastností.
Poznámka:
Tento modul se zaměřuje na vytváření a vyvolávání výjimek a přizpůsobení objektů výjimek. Vytváření vlastních tříd výjimek je mimo rozsah tohoto modulu.
Vytvoření objektu výjimky
Vytváření a vyvolávání výjimek z kódu je důležitým aspektem programování v jazyce C#. Schopnost vygenerovat výjimku v reakci na konkrétní podmínku, problém nebo chybu vám pomůže zajistit stabilitu aplikace.
Typ výjimky, který vytvoříte, závisí na problému s kódováním a měl by co nejblíže odpovídat zamýšlenému účelu výjimky.
Předpokládejme například, že vytváříte metodu s názvem GraphData , která provádí analýzu dat. Metoda přijímá datové pole jako vstupní parametr. Metoda očekává, že vstupní data budou v určité oblasti. Pokud metoda obdrží data, která jsou mimo očekávaný rozsah, vytvoří a vyvolá výjimku typu ArgumentException. Výjimku zpracuje někde v zásobníku volání kód, který je zodpovědný za poskytování dat.
Tady je několik běžných typů výjimek, které můžete použít při vytváření výjimky:
-
ArgumentExceptionneboArgumentNullException: Tyto typy výjimek použijte, pokud je volána metoda nebo konstruktor s neplatnou hodnotou argumentu nebo odkazem null. -
InvalidOperationException: Tento typ výjimky použijte, pokud provozní podmínky metody nepodporují úspěšné dokončení konkrétního volání metody. -
NotSupportedException: Tento typ výjimky použijte, pokud není podporována operace nebo funkce. -
IOException: Tento typ výjimky použijte, když selže vstupní/výstupní operace. -
FormatException: Tento typ výjimky použijte, pokud je nesprávný formát řetězce nebo dat.
Klíčové new slovo se používá k vytvoření instance výjimky. Můžete například vytvořit instanci ArgumentException typu výjimky následujícím způsobem:
ArgumentException invalidArgumentException = new ArgumentException();
Konfigurace a vyvolání přizpůsobených výjimek
Proces vyhození objektu výjimky zahrnuje vytvoření instance odvozené třídy výjimky, volitelnou konfiguraci vlastností výjimky a následné vyhození objektu pomocí klíčového slova throw.
Často je užitečné přizpůsobit výjimku s kontextovými informacemi, než ji vyvoláte. Konkrétní informace o aplikaci můžete zadat v rámci objektu výjimky konfigurací jeho vlastností. Například následující kód vytvoří objekt výjimky pojmenovaný invalidArgumentException s vlastností na míru Message, a pak vyvolá výjimku:
ArgumentException invalidArgumentException = new ArgumentException("ArgumentException: The 'GraphData' method received data outside the expected range.");
throw invalidArgumentException;
Poznámka:
Vlastnost Message výjimky je jen pro čtení. Proto musí být při vytváření instance objektu nastavena vlastní Message vlastnost.
Při přizpůsobení objektu výjimky je důležité poskytnout jasné chybové zprávy, které popisují problém a jak ho vyřešit. Můžete také zahrnout další informace, jako jsou trasování zásobníku a kódy chyb, které uživatelům pomůžou problém opravit.
Objekt výjimky lze také vytvořit přímo v příkazu throw . Například:
throw new FormatException("FormatException: Calculations in process XYZ have been cancelled due to invalid data format.");
Mezi důležité informace, které je potřeba vzít v úvahu při vyvolání výjimky, patří:
- Vlastnost
Messageby měla vysvětlit důvod výjimky. Citlivé informace nebo informace, které představují bezpečnostní problém, by ale neměly být vloženy do textu zprávy. - Vlastnost
StackTracese často používá ke sledování původu výjimky. Tato vlastnost řetězce obsahuje název metod v aktuálním zásobníku volání spolu s názvem souboru a číslem řádku v každé metodě, která je přidružena k výjimce. ObjektStackTracese vytvoří automaticky modulem CLR (Common Language Runtime) z boduthrowpříkazu. Výjimky musí být vyvolány z místa, kde by mělo začínat trasování zásobníku.
Kdy vyvolat výjimku
Metody by měly vyvolat výjimku, kdykoli nemohou dokončit zamýšlený účel. Vyvolaná výjimka by měla být založená na nejkonkrétnější dostupné výjimce, která odpovídá chybovým podmínkám.
Představte si scénář, ve kterém vývojář pracuje na aplikaci, která implementuje obchodní proces. Obchodní proces závisí na vstupu uživatele. Pokud vstup neodpovídá očekávanému datovému typu, metoda, která implementuje obchodní proces, vytvoří a vyvolá výjimku. Objekt výjimky lze nakonfigurovat s informacemi o konkrétních aplikacích v hodnotách vlastností. Následující ukázka kódu ukazuje scénář:
string[][] userEnteredValues = new string[][]
{
new string[] { "1", "two", "3"},
new string[] { "0", "1", "2"}
};
foreach (string[] userEntries in userEnteredValues)
{
try
{
BusinessProcess1(userEntries);
}
catch (Exception ex)
{
if (ex.StackTrace.Contains("BusinessProcess1") && (ex is FormatException))
{
Console.WriteLine(ex.Message);
}
}
}
static void BusinessProcess1(string[] userEntries)
{
int valueEntered;
foreach (string userValue in userEntries)
{
try
{
valueEntered = int.Parse(userValue);
// completes required calculations based on userValue
// ...
}
catch (FormatException)
{
FormatException invalidFormatException = new FormatException("FormatException: User input values in 'BusinessProcess1' must be valid integers");
throw invalidFormatException;
}
}
}
V této ukázce kódu volají příkazy nejvyšší úrovně metodu BusinessProcess1 a předávají řetězcové pole, které obsahuje uživatelem zadané hodnoty. Metoda BusinessProcess1 očekává vstupní hodnoty uživatele, které lze převést na celé číslo. Když metoda narazí na data s neplatným formátem, vytvoří instanci FormatException typu výjimky pomocí přizpůsobené Message vlastnosti. Metoda pak vyvolá výjimku. Výjimka je zachycena v příkazech nejvyšší úrovně jako objekt s názvem ex. Vlastnosti objektu ex jsou zkoumány před zobrazením zprávy výjimky uživateli. Nejprve kód zkontroluje StackTrace vlastnost a zjistí, jestli obsahuje "BusinessProcess1". Za druhé, objekt ex výjimky je ověřen jako typ FormatException.
Opětovné vyvolání výjimek
Kromě vyvolání nové výjimky lze použít opětovné vyvolání výjimky throw z bloku catch kódu. V tomto případě throw nepřijímá operand výjimky.
catch (Exception ex)
{
// handle or partially handle the exception
// ...
// re-throw the original exception object for further handling down the call stack
throw;
}
Při opětovném vyvolání výjimky se použije původní objekt výjimky, takže nepřijdete o žádné informace o výjimce. Pokud chcete vytvořit nový objekt výjimky, který zabalí původní výjimku, můžete původní výjimku předat jako argument konstruktoru nového objektu výjimky. Například:
catch (Exception ex)
{
// handle or partially handle the exception
// ...
// create a new exception object that wraps the original exception
throw new ApplicationException("An error occurred", ex);
}
Pro scénář aplikace BusinessProcess1 zvažte následující aktualizace:
- Metoda
BusinessProcess1byla aktualizována tak, aby obsahovala další podrobnosti.BusinessProcess1nyní narazí na dva problémy a musí vygenerovat výjimky pro každý problém. - Aktualizovali jsme příkazy nejvyšší úrovně. Příkazy na nejvyšší úrovni nyní volají metodu
OperatingProcedure1.OperatingProcedure1zavoláBusinessProcess1v rámcitrybloku kódu. - Metoda
OperatingProcedure1dokáže zpracovat jeden z typů výjimek a částečně zpracovat druhý. Po zpracování částečně zpracované výjimkyOperatingProcedure1je nutné znovu vyvolat původní výjimku.
Následující ukázka kódu ukazuje aktualizovaný scénář:
try
{
OperatingProcedure1();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Exiting application.");
}
static void OperatingProcedure1()
{
string[][] userEnteredValues = new string[][]
{
new string[] { "1", "two", "3"},
new string[] { "0", "1", "2"}
};
foreach(string[] userEntries in userEnteredValues)
{
try
{
BusinessProcess1(userEntries);
}
catch (Exception ex)
{
if (ex.StackTrace.Contains("BusinessProcess1"))
{
if (ex is FormatException)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Corrective action taken in OperatingProcedure1");
}
else if (ex is DivideByZeroException)
{
Console.WriteLine(ex.Message);
Console.WriteLine("Partial correction in OperatingProcedure1 - further action required");
// re-throw the original exception
throw;
}
else
{
// create a new exception object that wraps the original exception
throw new ApplicationException("An error occurred - ", ex);
}
}
}
}
}
static void BusinessProcess1(string[] userEntries)
{
int valueEntered;
foreach (string userValue in userEntries)
{
try
{
valueEntered = int.Parse(userValue);
checked
{
int calculatedValue = 4 / valueEntered;
}
}
catch (FormatException)
{
FormatException invalidFormatException = new FormatException("FormatException: User input values in 'BusinessProcess1' must be valid integers");
throw invalidFormatException;
}
catch (DivideByZeroException)
{
DivideByZeroException unexpectedDivideByZeroException = new DivideByZeroException("DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero");
throw unexpectedDivideByZeroException;
}
}
}
Aktualizovaný vzorový kód vytvoří následující výstup:
FormatException: User input values in 'BusinessProcess1' must be valid integers
Corrective action taken in OperatingProcedure1
DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero
Partial correction in OperatingProcedure1 - further action required
DivideByZeroException: Calculation in 'BusinessProcess1' encountered an unexpected divide by zero
Exiting application.
Čemu se vyhnout při vyhazování výjimek
Následující seznam uvádí postupy, které se mají vyhnout při vyvolání výjimek:
- Nepoužívejte výjimky ke změně toku programu jako součást běžného provádění. Pomocí výjimek můžete hlásit a zpracovat chybové stavy.
- Výjimky by se neměly vracet jako návratová hodnota nebo parametr místo vyvolání.
- Nevyvolávejte
System.Exception,System.SystemException,System.NullReferenceExceptionani záměrněSystem.IndexOutOfRangeExceptionz vlastního zdrojového kódu. - Nevytvávejte výjimky, které se dají vyvolat v režimu ladění, ale ne v režimu vydání. K identifikaci chyb za běhu během vývojové fáze použijte
Debug.Assertmísto toho.
Poznámka:
Tato Debug.Assert metoda je nástroj pro zachycení chyb logiky během vývoje. Ve výchozím nastavení metoda Debug.Assert funguje pouze v sestaveních pro ladění. V ladicích relacích můžete zkontrolovat Debug.Assert podmínku, která by nikdy neměla nastat. Metoda má dva parametry: logickou podmínku ke kontrole a volitelnou řetězcovou zprávu, která se má zobrazit, pokud je podmínka false.
Debug.Assert by se nemělo používat místo vyvolání výjimky, což je způsob, jak zvládnout výjimečné situace během normálního provádění kódu. Měli byste použít Debug.Assert k zachycení chyb, ke kterým by nikdy nedošlo, a k zpracování chyb, ke kterým může dojít během normálního provádění programu, použijte výjimky.
Rekapitulace
Tady je několik důležitých věcí, které je potřeba si z této lekce zapamatovat:
- Při vytváření a vyvolání výjimky musí typ výjimky odpovídat zamýšlenému účelu výjimky co nejblíže.
- K
throwvýjimce vytvoříte instanci odvozené třídy výjimky, nakonfigurujete její vlastnosti a pak použijetethrowklíčové slovo. - Při vytváření objektu výjimky je důležité poskytnout jasné chybové zprávy a další informace, které uživatelům pomůžou problém opravit.