CodeGym /课程 /C# SELF /try-catch语法:错误处理

try-catch语法:错误处理

C# SELF
第 13 级 , 课程 1
可用

1. 入门

理想情况下,代码应该是完美的。但现实是,即使是最细心的程序员也总会遇到意外情况:比如找不到文件,用户输入了字符串而不是数字,网络突然断了,或者数据库返回的东西和预期不一样。

如果这些问题没人管——程序就会直接“崩溃”,有时候还会冒出一堆神秘的错误信息和stack trace(调用堆栈)。这可不是用户或者未来的技术支持想看到的。我们得学会“抓住”这些错误并做出反应:优雅地结束程序,输出人类能看懂的提示,甚至有时候还能现场修复问题。

try-catch——就是告诉编译器和运行环境:“试试执行这段代码。如果出问题了,别慌,让我来处理!”

2. try-catch的基本语法

整体结构其实很简单:


try
{
    // 这里写危险(或者可能有风险)的代码
}
catch (ExceptionType variableName)
{
    // 这里写遇到ExceptionType类型异常时要干嘛
}
try-catch的基本语法
  • try块——就是“危险区”。把那些可能“出事儿”的操作放这里。
  • catch块——捕获特定类型的异常。如果try里抛出异常,程序会立刻跳到第一个匹配的catch,而try里“出事儿”后面的代码就不会再执行了。

例子:简单的异常处理

假设我们之前讲过的小型计算器现在能做除法了。但用户可能会输入0!看看没处理错误时会发生什么:

int a = 10;
int b = 0;
int result = a / b; // 砰!System.DivideByZeroException
Console.WriteLine(result);

程序会因为DivideByZeroException异常直接崩溃:

未处理的异常。System.DivideByZeroException: 尝试除以零。

现在用try-catch来“修一下”:

int a = 10;
int b = 0;

try
{
    int result = a / b; // 危险操作
    Console.WriteLine("除法结果: " + result);
}
catch (DivideByZeroException ex)
{
    Console.WriteLine("哎呀!不能除以零: " + ex.Message);
}

现在程序不会“崩溃”了。控制台会显示不能除以零的提示:

哎呀!不能除以零: 尝试除以零。

3. try-catch是怎么工作的:一步一步看

其实try里可以写很多行代码。如果其中某个操作抛出异常,程序会立刻跳到最近的、匹配的catch。在try块里出错后的代码都不会再执行。

来看个大一点的例子:

try
{
    Console.WriteLine("开始...");
    int[] numbers = { 1, 2, 3 };
    Console.WriteLine(numbers[1]);    // 没问题
    Console.WriteLine(numbers[5]);    // 错误:数组越界
    Console.WriteLine("这条消息不会出现了!");
}
catch (IndexOutOfRangeException)
{
    Console.WriteLine("错误:试图访问不存在的数组元素");
}

控制台输出会是这样:

开始...
2
错误:试图访问不存在的数组元素

Process finished with exit code 0.

这个程序是怎么运行的?

  • 先输出“开始...”
  • 然后程序试图输出numbers[1]——就是2。
  • 当执行到numbers[5]时,“炸了”,抛出IndexOutOfRangeException
  • 程序立刻跳到catch块,Console.WriteLine("这条消息不会出现了!");被跳过。
  • 控制台会显示catch里的消息。

4. 能不能对不同类型的错误分别处理?

当然可以!我们可以写多个catch块,对不同类型的异常做不同处理。很方便,比如一个操作是读文件(可能会有FileNotFoundException),另一个是除法(可能会有DivideByZeroException)。

try
{
    // 你的危险代码
}
catch (DivideByZeroException)
{
    Console.WriteLine("除以零错误");
}
catch (IndexOutOfRangeException)
{
    Console.WriteLine("错误:数组索引越界");
}
catch (Exception ex)
{
    Console.WriteLine("遇到未知错误: " + ex.Message);
}

这里最后一个catch类型是Exception——“万能捕手”。它会捕获前面没被抓到的所有异常。但注意:如果你把它写在最前面,后面的catch就永远不会被执行!所以“宽泛”的catch要放最后。

5. 异常对象长啥样?

catch块里我们可以选填一个变量——比如catch (Exception ex)。它包含了所有关于错误的信息:消息、错误类型、调用堆栈、嵌套异常等。

来看个小例子:

try
{
    string? text = null;
    Console.WriteLine(text.Length); // 哎呦!NullReferenceException
}
catch (NullReferenceException ex)
{
    Console.WriteLine("捕获到异常: " + ex.Message);
    Console.WriteLine("调用堆栈: " + ex.StackTrace);
}

这种方式在调试复杂错误时特别有用:你总能看到程序“摔倒”在哪儿、为啥摔倒。

6. 抓住错误后继续运行

在真实的、尤其是面向用户的应用里,出错并不是世界末日。比如用户输错了文件路径,这很正常。这还不至于让程序“崩溃”重启。我们可以让他再试一次。

下面这个例子展示了一个简单但实用的做法:我们把读文件的操作放在循环里,如果出错就提示用户重试。没有恐慌,没有红色报错屏。

bool success = false;
while (!success)
{
    Console.Write("请输入文件名: ");
    string fileName = Console.ReadLine() ?? "";

    try
    {
        string content = File.ReadAllText(fileName);
        Console.WriteLine("文件读取成功!");
        success = true; // 太棒了!
    }
    catch (FileNotFoundException)
    {
        Console.WriteLine("错误:文件未找到。请再试一次。");
    }
}

这里的核心思想——不是简单地捕获异常,而是合理地处理它:我们不让程序崩溃,而是切换到“再来一次”的模式。用户得到了清晰的提示,程序有了第二次机会,你也会收获感谢和尊重。

7. 用try-catch时常见的错误

错误1:把所有代码都包进一个万能try-catch里。
这样看起来很省事——一个try,一个catch (Exception),好像“全都安全了”。但实际上你会失去对问题的掌控。根本不知道到底哪儿出错了,也不知道你到底在处理什么异常。结果不是更安全,反而彻底丢失了诊断能力。

错误2:捕获异常却啥也不做。
生活中的例子:

try
{
    // 可能有风险的操作
}
catch
{
    // 什么都不说...
}
这种代码的意思就是:“出事儿了...算了。” 这很危险:程序可能会在错误状态下继续运行,你甚至都不知道出过错。至少要输出个提示或者记录下错误。千万别写空的 catch

错误3:捕获过于宽泛的异常类型。
如果你捕获Exception,但其实你知道可能会出现FormatException或者FileNotFoundException,——你就失去了针对具体问题做出合适反应的机会。你的catch越精确,程序在特殊情况下就越可控、越靠谱。

8. 不推荐用异常做什么

有时候新手会把异常当成...普通的逻辑控制手段,比如:

try
{
    if (x < 0) throw new Exception("x必须>=0");
}
catch (Exception)
{
    // 回滚状态,继续运行...
}

千万别这样!异常是用来处理意外、罕见的情况(比如读文件失败、网络故障等),不是用来做普通的用户数据校验的。遇到这种情况请用条件语句(ifelse)和特殊返回值来处理。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION