• 友链

  • 首页

  • 文章归档
h u a n b l o g
h u a n b l o g

欢

HI,Friend

04月
15
C#

异常处理程序

发表于 2022-04-15 • 字数统计 7483 • 被 1,341 人看爆

try语句

try语句用来指明为避免出现异常而被保护的代码段,并在发生异常时提供代码处理异常。

组成

由3部分组成

  • try块包含为避免出现异常而被保护的代码。
  • catch子句部分含有一个或多个catch子句。这些是处理异常的代码段,它们也称为是异常处理程序。
  • finally块含有在所有情况下都要被执行的代码,无论有没有异常发生。

try语句结构.png

处理异常

int x = 10;
try
{
    int y = 0;
    x /= y;     //抛出异常
}
catch
{
    //处理异常代码
    Console.WriteLine("Handling all exceptions -- Keep on Running");
}

Console.ReadKey();

结果

Handling all exceptions -- Keep on Running

异常类

异常类派生自System.Exception类

异常层次结构.png

属性类型描述
Messagestring这个属性含有解释异常原因的消息
StackTracestring这个属性含有描述异常发生在何处的信息
InnerExceptionException如果当前异常是由另一个异常引起的,这个属性包含前一个异常的引用
HelpLinkstring这个属性可以被应用程序定义的异常设置,为异常原因信息提供URN或URL
Sourcestring如果没有被应用程序定义的异常设定,那么这个属性含有异常所在的程序集的名称

catch子句

用于处理异常

有3中形式,允许不同级别的处理

catch子句3种形式.png

  • 一般catch子句能接受任何异常,但不能确定引发异常的类型。这只允许对任何可能发生的异常的普通处理和清理。
  • 特定catch子句形式把一个异常类的名称作为参数。它匹配该指定类或派生自它的异常类的异常。
  • 带对象的特定catch子句提供关于异常的最多信息。它匹配该指定类的异常,或派生自它的异常类的异常。它还给出一个异常实例(称为异常变量),是一个对CLR创建的异常对象的引用。可以在catch子句块内部访问异常变量的属性,以获取关于引起的异常的详细信息。

例

catch(IndexOutOfRangeException e) {
    Console.WriteLine("Message:{0}", e.Message);
    Console.WriteLine("Message:{0}", e.Source);
    Console.WriteLine("Message:{0}", e.StackTrace);
}

实例
下列代码为指定处理

int x = 10;
try
{
    int y = 0;
    x /= y;     //抛出异常
}
catch(DivideByZeroException)
{
    //处理异常代码
    Console.WriteLine("Handling all exceptions");
}

进一步修改

int x = 10;
try
{
    int y = 0;
    x /= y;     //抛出异常
}
catch(DivideByZeroException e)
{
    //处理异常代码
    Console.WriteLine("Message:{0}", e.Message);
    Console.WriteLine("Message:{0}", e.Source);
    Console.WriteLine("Message:{0}", e.StackTrace);
}

结果

Message:尝试除以零。
Message:try语句
Message: 在 try语句.Program.Main(String[] args) 位置 x:\xx\xx\xx\Program.cs:行号 17

catch子句段规则

  • 特定catch子句必须以一种顺序排列,最明确的异常类型第一,直到最普通的类型。例如,如果声明了一个派生自NullRefrenceException的异常类,那么派生异常类型的catch子句应该被列在NullReferenceException的catch子句之前。
  • 如果有一个一般catch子句,它必须是最后一个,并且在所有特定catch子句之后。不鼓励使用一般catch子句,因为它允许程序继续执行隐藏错误,让程序处于一种未知的状态。应尽可能使用特定catch子句。

try中catch子句段结构.png

finally块

  • 如果在try块内部没有异常发生,那么在try块的结尾,控制流跳过任何catch子句并到finally块。
  • 如果在try块内部发生了异常,那么在catch子句段中无论哪一个适当的catch子句被执行,接着就是finally块的执行。

finally块执行.png

即使try块中有return语句或在catch块中抛出一个异常,finally块也总是会在返回到调用代码之前执行。

例
下面代码中,在try块的中间有一条return语句,它在某条件下被执行。

static void finallyFunc ()
{
    int inVal = 5;
    try
    {
        if (inVal < 10)
        {
            Console.Write("First Branch - ");
            return;
        }
        else
        {
            Console.Write("Second Branch - ");
        }
    }
    finally
    {
        //处理异常代码
        Console.WriteLine("In finally statement");
    }

}
static void Main(string[] args)
{
    finallyFunc();
    Console.ReadKey();
}

结果

First Branch - In finally statement

为异常寻找处理程序

  • 如果在try块内发生了异常,系统会查看是否有任何一个catch子句能处理该异常。
  • 如果找到了适当的catch子句,以下3项中的1项会发生。
    • 该catch子句被执行。
    • 如果有finally块,那么它被执行。
    • 执行在try语句的尾部继(也就是说,在finally块之后,或如果没有finally块,就在最后一个catch子句之后)。

处理异常程序.png

异常处理一般法则
异常处理一般法则.png

实例
调用栈的示例
Main调用方法A,A调用方法B


class MyClass
{
    public void A()
    {
        try
        {
            B();
        }
        catch (NullReferenceException)
        {
            Console.WriteLine("catch子句中 A()");
        }
        finally
        {
            Console.WriteLine("finally子句中 A()");
        }
    }

    void B()
    {
        int x = 10, y = 0;
        try
        {
            x /= y;
        }
        catch (IndexOutOfRangeException)
        {
            Console.WriteLine("catch子句中 B()");
        }
        finally
        {
            Console.WriteLine("finally子句中 B()");
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        MyClass MCls = new MyClass();

        try
        {
            MCls.A();
        }
        catch (DivideByZeroException e)
        {
            Console.WriteLine("catch子句中 Main()");
        }
        finally
        {
            Console.WriteLine("finally子句中 Main()");
        }

        Console.WriteLine("Main中try语句结束");


        Console.ReadKey();
    }
}

结果

finally子句中 B()
finally子句中 A()
catch子句中 Main()
finally子句中 Main()
Main中try语句结束

分析

(1)Main调用A,A调用B,B遇到一个DivideByZeroExceprion异常。
(2)系统检查B的catch段寻找匹配的catch子句。虽然它有一个IndexOutOfRangeException的句,但没有DivideByZeroException的。
(3)系统然后延着调用栈向下移动并检查A的catch段,在那里它发现A也没有匹配的catch子句。
(4)系统继续延调用栈向下,并检查Nain的catch子句部分,在那里它发现Nain确实有一个DivideByZeroException的catch子句。
(5)尽管匹配的catch子句现在被定位了,但并不执行。相反,系统回到栈的顶端,执行B的finally子句,并把B从调用栈中弹出。
(6)系统移动到A,执行它的finally子句,并把A从调用栈中弹出。
(7)最后,Main的匹配catch子句被执行,接着是它的finally子句。然后执行在Nain的try语句结尾之后继续。
寻找异常处理程序过程.png

抛出异常

可以使用throw语句使代码显式地引发一个异常

语法

throw ExceptionObject;

实例
下面的代码定义了一个名称为PrintArg的方法,它带一个string参数并把它打印出来。在try块内部,它首先做检查以确认该参数不是null。如果是null,它创建一个ArgumenNullException实例并抛出它。该异常实例在catch语句中被捕获,并且该出错消息被打印。Nain调用该方法两次:一次用null参数,然后用一个有效参数。

class MyClass
{
    public static void PrintArg(string arg)
    {
        try
        {
            if(arg == null)
            {
                ArgumentNullException myEx = new ArgumentNullException("arg");
                throw myEx;
            }
            Console.WriteLine(arg);

        }
        catch (ArgumentNullException e)
        {
            Console.WriteLine("Message: {0}", e.Message);
        }
    }
}


class Program
{
    static void Main(string[] args)
    {
        string s = null;
        MyClass.PrintArg(s);
        MyClass.PrintArg("Hi there!");

        Console.ReadKey();
    }
}

结果

Message: 值不能为 null。
参数名: arg
Hi there!

不带异常对象的抛出

在catch内,throw可以不带异常使用
  • 这种形式重新抛出当前异常,系统继续它的搜索,为该异常寻找另外的处理代码。
  • 这种形式只能用在catch语句内部。

实例

class MyClass
{
    public static void PrintArg(string arg)
    {
        try
        {
            try
            {
                if(arg==null)
                {
                    ArgumentNullException myEx = new ArgumentNullException("arg");
                    throw myEx;
                }
                Console.WriteLine(arg);
            }
            catch(ArgumentNullException e)
            {
                Console.WriteLine("Inner Catch: {0}", e.Message);
                throw;      //重新抛出异常,没有附加参数
            }
        }
        catch
        {
            Console.WriteLine("Outer Catch: Handling an Exception");
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        string s = null;
        MyClass.PrintArg(s);

        Console.ReadKey();
    }
}

结果

Inner Catch: 值不能为 null。
参数名: arg
Outer Catch: Handling an Exception

分享到:
预处理指令
其它异步模式
  • 文章目录
  • 站点概览
欢

网红 欢

你能抓到我么?

Email RSS
看爆 Top5
  • mac系统版本与Xcode版本有冲突 4,086次看爆
  • JAVA_HOME环境配置问题 3,736次看爆
  • AssetBundle使用 3,504次看爆
  • VSCode配置C++开发环境 3,261次看爆
  • Lua反射 3,137次看爆

Copyright © 2025 欢 粤ICP备2020105803号-1

由 Halo 强力驱动 · Theme by Sagiri · 站点地图