在这里,您将学习使用try,catch和finally块在C#中进行异常处理的知识。
必须处理应用程序中的异常,以防止程序崩溃和意外结果,记录异常并继续执行其他功能。C#提供内置支持使用 try,catch和finally块 来处理异常。
语法:
try { // 将代码放在这里可能会引发异常 } catch { // 在这里处理异常 } finally { // 最终清理代码 }
try 块:任何可能引发异常的可疑代码都应放在一个try{ }块中。在执行过程中,如果发生异常,则控制流跳至第一个匹配catch块。
catch 块:catch块是异常处理程序块,您可以在其中执行一些操作,例如记录和审核异常。catch块采用异常类型的参数,您可以使用该参数获取异常的详细信息。
finally 块:finally无论是否引发异常,都将始终执行该块。通常,finally应该使用一个块来释放资源,例如,关闭在try块中打开的任何流或文件对象。
如果您输入非数字字符,则以下内容可能会引发异常。
class Program { static void Main(string[] args) { Console.WriteLine("Enter a number: "); var num = int.Parse(Console.ReadLine()); Console.WriteLine($"Squre of {num} is {num * num}"); } }
要在上面的示例中处理可能的异常,请将代码包装在一个try块中,然后在catch块中处理异常,如下所示。
class Program { static void Main(string[] args) { try { Console.WriteLine("Enter a number: "); var num = int.parse(Console.ReadLine()); Console.WriteLine($"Squre of {num} is {num * num}"); } catch { Console.Write("Error occurred."); } finally { Console.Write("Re-try with a different number."); } } }
在上面的示例中,我们将此代码包装在一个try块中。如果try块内发生异常,则程序将跳转到该catch块。在catch块内,我们将显示一条消息以指示用户有关其错误的信息,在finally块内,我们将显示一条有关运行程序后的操作的消息。
try块必须跟catch或finally或两种嵌段。在try不使用块catch或finally块将给出一个编译时错误。
理想情况下,catch块应包含内置或自定义异常类的参数以获取错误详细信息。以下包括Exception捕获所有类型的异常的type参数。
class Program { static void Main(string[] args) { try { Console.WriteLine("Enter a number: "); var num = int.parse(Console.ReadLine()); Console.WriteLine($"Squre of {num} is {num * num}"); } catch(Exception ex) { Console.Write("Error info:" + ex.Message); } finally { Console.Write("Re-try with a different number."); } } }
您可以使用catch具有不同异常类型参数的多个块。这称为异常过滤器。当您想以不同的方式处理不同类型的异常时,异常过滤器很有用。
class Program { static void Main(string[] args) { Console.Write("Please enter a number to divide 100: "); try { int num = int.Parse(Console.ReadLine()); int result = 100 / num; Console.WriteLine("100 / {0} = {1}", num, result); } catch(DivideByZeroException ex) { Console.Write("不能被零除。请再试一次."); } catch(InvalidOperationException ex) { Console.Write("无效操作。请再试一次."); } catch(FormatException ex) { Console.Write("不是有效格式。 请再试一次."); } catch(Exception ex) { Console.Write("发生错误!请再试一次."); } } }
在上面的示例中,我们指定了catch具有不同异常类型的多个块。我们可以根据错误向用户显示适当的消息,因此用户不会再次重复相同的错误。
在同一 try..catch语句中不允许使用无参数catch块和带有Exception参数的catch块,因为它们都执行相同的操作。
try { //可能引发异常的代码 } catch //不能同时具有catch和catch(Exception 异常) { Console.WriteLine("Exception occurred"); } catch(Exception ex) //不能同时具有catch和catch(异常异常) { Console.WriteLine("Exception occurred"); }
另外,无参数 catch 块 catch {}或通用 catch 块 catch (Exception ex){}必须是最后一个块。如果在 catch {}或 catch (Exception ex)块之后还有其他 catch 块,编译器将给出错误。
示例:无效的catch 捕获
try { //可能引发异常的代码 } catch { // 该捕获块必须是最后一个块 } catch (NullReferenceException nullEx) { Console.WriteLine(nullEx.Message); } catch (InvalidCastException inEx) { Console.WriteLine(inEx.Message); }
finally块是可选块,应在try或catch块之后。无论是否发生异常,都将始终执行 finally 块。finally块通常用于清理代码,例如处理非托管对象。
示例:finally块
static void Main(string[] args) { FileInfo file = null; try { Console.Write("Enter a file name to write: "); string fileName = Console.ReadLine(); file = new FileInfo(fileName); file.AppendText("Hello World!") } catch(Exception ex) { Console.WriteLine("Error occurred: {0}", ex.Message ); } finally { // 在这里清理文件对象; file = null; } }
finally不允许使用 多个块。另外,finally块不能包含return,continue或break关键字。它不允许控制权离开finally块。
C#允许嵌套try-catch块。当使用嵌套的try-catch块时,将在发生异常catch的try块之后的第一个匹配块中捕获异常。
static void Main(string[] args) { var divider = 0; try { try { var result = 100/divider; } catch { Console.WriteLine("Inner catch"); } } catch { Console.WriteLine("Outer catch"); } }
Inner catch
catch在上面的示例中,将执行一个内部块,因为它是catch处理所有异常类型的第一个块。
如果没有与抛出的异常类型匹配的内部catch块,则控制将流向外部catch块,直到找到合适的异常筛选器。看下面的实例。
static void Main(string[] args) { var divider = 0; try { try { var result = 100/divider; } catch(NullReferenceException ex) { Console.WriteLine("Inner catch"); } } catch { Console.WriteLine("Outer catch"); } }
Outer catch
在上面的示例中,将引发类型异常 DivideByZeroException 。由于内部catch块仅处理NullReferenceTypeException,因此将由外部catch块处理。