C# 中的异常处理
在这里,您将学习如何使用 try、catch 和 finally 块在 C# 中处理异常。
必须处理应用程序中的异常,以防止程序崩溃、出现意外结果、记录异常并继续执行其他功能。C# 提供内置支持,使用 try
、catch
和 finally
块来处理异常。
trycatchfinally
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
块,或两者兼有。没有 catch
或 finally
块的 try
块将导致编译时错误。理想情况下,catch
块应包含内置或自定义异常类的参数,以获取错误详细信息。以下包含 Exception
类型参数,该参数捕获所有类型的异常。
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
块与不同的异常类型参数一起使用。这称为异常过滤器。当您希望以不同方式处理不同类型的异常时,异常过滤器很有用。
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("Cannot divide by zero. Please try again.");
}
catch(InvalidOperationException ex)
{
Console.Write("Invalid operation. Please try again.");
}
catch(FormatException ex)
{
Console.Write("Not a valid format. Please try again.");
}
catch(Exception ex)
{
Console.Write("Error occurred! Please try again.");
}
}
}
在上面的示例中,我们指定了多个具有不同异常类型的 catch
块。我们可以根据错误向用户显示适当的消息,以便用户不再重复相同的错误。
catch
块。带有基异常类型的 catch
块必须是最后一个块。无效的 catch 块
在同一个 try
-catch 语句中,不允许使用无参数 catch
块和带 Exception
参数的 catch
块,因为它们执行相同的操作。
try
{
//code that may raise an exception
}
catch //cannot have both catch and catch(Exception ex)
{
Console.WriteLine("Exception occurred");
}
catch(Exception ex) //cannot have both catch and catch(Exception ex)
{
Console.WriteLine("Exception occurred");
}
此外,无参数的 catch 块 catch{ }
或通用 catch 块 catch(Exception ex)
必须是最后一个块。如果在 catch
或 catch(Exception ex)
块之后还有其他 catch
块,编译器将报错。
try
{
//code that may raise an exception
}
catch
{
//code that may raise an exception
}
catch
{
// this catch block must be last block
}
catch (NullReferenceException nullEx)
{
Console.WriteLine(nullEx.Message);
}
catch (InvalidCastException inEx)
{
Console.WriteLine(inEx.Message);
}
finally 块
finally
块是一个可选块,应位于 try
或 catch 块之后。无论是否发生异常,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
{
// clean up file object here;
file = null;
}
}
finally
块。此外,finally
块不能包含 return、continue 或 break 关键字。它不允许控制流离开 finally
块。嵌套的 try-catch
C# 允许嵌套的 try-catch 块。当使用嵌套的 try-catch 块时,异常将被发生异常的 try
块后面的第一个匹配的 catch
块捕获。
static void Main(string[] args)
{
var divider = 0;
try
{
try
{
var result = 100/divider;
}
catch
{
Console.WriteLine("Inner catch");
}
}
catch
{
Console.WriteLine("Outer 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");
}
}
在上面的示例中,将引发 DivideByZeroException
类型的异常。因为内部 catch
块只处理 NullReferenceTypeException
,所以它将由外部 catch
块处理。