必须处理应用程序中的异常,以防止程序崩溃和意外结果,记录异常并继续执行其他功能。C#提供内置支持使用 try,catch和finally块 来处理异常。
语法:
try
{
// 将代码放在这里可能会引发异常
}
catch
{
// 在这里处理异常
}
finally
{
// 最终清理代码
}try 块:任何可能引发异常的可疑代码都应放在一个try{ }块中。在执行过程中,如果发生异常,则控制流跳至第一个匹配catch块。
catch 块:catch块是异常处理程序块,您可以在其中执行一些操作,例如记录和审核异常。catch块采用异常类型的参数,您可以使用该参数获取异常的详细信息。
finally 块:finally无论是否引发异常,都将始终执行该块。通常,finally应该使用一个块来释放资源,例如,关闭在try块中打开的任何流或文件对象。
如果您输入非数字字符,则以下内容可能会引发异常。
示例:C#程序异常示例
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块中处理异常,如下所示。
示例:使用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参数。
示例:使用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(Exception ex)
{
Console.Write("Error info:" + ex.Message);
}
finally
{
Console.Write("Re-try with a different number.");
}
}
}异常过滤器
您可以使用catch具有不同异常类型参数的多个块。这称为异常过滤器。当您想以不同的方式处理不同类型的异常时,异常过滤器很有用。
示例:C# 异常过滤器
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具有不同异常类型的多个块。我们可以根据错误向用户显示适当的消息,因此用户不会再次重复相同的错误。
注意:
不允许具有相同异常类型的多个catch块。具有基异常类型的catch块必须是最后一个块。
无效的catch块
在同一 try..catch语句中不允许使用无参数catch块和带有Exception参数的catch块,因为它们都执行相同的操作。
示例:无效的 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 块
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块。
嵌套try-catch
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 catchcatch在上面的示例中,将执行一个内部块,因为它是catch处理所有异常类型的第一个块。
如果没有与抛出的异常类型匹配的内部catch块,则控制将流向外部catch块,直到找到合适的异常筛选器。看下面的实例。
示例:嵌套 try..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块处理。