猿教程 Logo

C# 异常处理

我们在前面的章节中看到,如果程序中有错误,CLR或程序代码抛出异常。 这些异常需要处理以防止程序崩溃。 C#提供了内置的支持来处理异常,使用try,catch&finally块。

语法格式:

try
{
    // code that may raise exceptions
}
catch(Exception ex)
{
    // handle exception
}
finally
{
    // final cleanup code
}

根据上述语法,将代码放在try块中,可能引发异常,后面跟catch或finally块。 将变量声明保留在try块之外,以便可以在catch和finally块中访问它们。

让我们看看如何使用try&catch块来处理异常。 参考下面的代码可以引发异常。

相关实例:

class Program
{
    static void Main(string[] args)
    {
        Console.Write("Enter Student Name: ");

        string studentName = Console.ReadLine();

        IListstudentList = FindAllStudentFromDatabase(studentName);

        Console.WriteLine("Total {0}: {1}", studentName, studentList.Count());

        Console.ReadKey();
    }

    private static IListFindAllStudentFromDatabase(string studentName)
    {
        var studentList = // find all students with same name from the database 

        return studentList;
    }
}

在上面的示例中,它显示具有相同名称的学生总数。 假设FindAllStudentFromDatabase()方法从数据库获取具有相同名称的学生列表。

如果至少有一个学生存在指定的名称,上述示例将正常工作,否则将引发NullReferenceException。 我们不想向用户显示异常消息并停止执行。 所以,我们需要使用try catch块来处理异常,如下所示。

相关实例:

class Program
{
    static void Main(string[] args)
    {
        Console.Write("Enter Student Name: ");

        string studentName = Console.ReadLine();
        
        try
        {
            IListstudentList = FindAllStudentFromDatabase(studentName);

            Console.WriteLine("Total {0}: {1}", studentName, studentList.Count());
        }
        catch(Exception ex)
        {
            Console.Write("No Students exists for the specified name.");
        }

        Console.ReadKey();
    }

    private static IListFindAllStudentFromDatabase(string studentName)
    {
        var studentList = // find all students with same name from the database 

        return studentList;
    }
}

从上面的例子可以看到,如果studentList为null,studentList.Count()可能引发异常。 所以包装这段代码到try块。 try块简单告诉编译器监视异常的代码。 在try块中引发的异常必须使用catch块处理。

重点

try块必须后跟catch或finally或两个块。 try块没有catch或finally块将给出编译时错误。


Catch板块

在try块中引发的异常可以使用catch块来处理,如上面的例子所示。 catch块中的代码只会在发生异常时执行。

多个catch块也可以用不同的异常类型指定,称为异常过滤器。 当你想以不同的方式处理不同的异常时,多重catch块是有用的。

相关实例:

class Program
{
    static void Main(string[] args)
    {
        Console.Write("Please enter two numbers: ");
        
        try
        {
            int num1 = int.Parse(Console.ReadLine());
            int num2 = int.Parse(Console.ReadLine());

            int result = num1 / num2;

            Console.WriteLine("{0} / {1} = {2}", num1, num2, result);
        }
        catch(DivideByZeroException ex)
        {
            LogError(ex);
            Console.Write("Cannot divide by zero. Please try again.");
        }
        catch(InvalidOperationException ex)
        {
            LogError(ex);
            Console.Write("Not a valid number. Please try again.");
        }
        catch(FormatException  ex)
        {
            LogError(ex);
            Console.Write("Not a valid number. Please try again.");
        }

        Console.ReadKey();
    }

}

在上面的例子中,我们指定了一个具有不同异常类型的多重捕获块,以便我们可以向用户显示适当的消息,这取决于错误,因此用户不会再重复同样的错误。

重点

不允许具有相同异常类型的多个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
{ 
    // 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)
{
    int zero = 0;    
    
    try
    {
        int result = 5/zero;  // this will throw an exception       
            
    }
    catch(Exception ex)
    {
        Console.WriteLine("Inside catch block. Exception: {0}", ex.Message );
    }
    finally
    {
        Console.WriteLine("Inside finally block.");

    }
}

运行结果:

Inside catch block. Exception: Attempted to divide by zero.
Inside finally
重点

不允许多个finally块。 此外,finally块不能有return, continue或break关键字。 它不允许控制离开finally块。


嵌套try-catch

C#允许嵌套的try catch块。 在嵌套的try catch块中,在发生异常的try块之后的catch块中将捕获异常。

相关实例:

static void Main(string[] args)
{
    Student std = null;
           
    try
    {
        try
        {
            std.StudentName = "";
        }
        catch
        {
            Console.WriteLine("Inner catch");
        }
    }
    catch
    {
        Console.WriteLine("Outer catch");
    }
}

运行结果:

Inner catch

如果没有任何内部catch块具有适当的异常类型,则异常将流向外部catch块,直到找到适当的异常过滤器。 请参考以下示例。

相关实例:

static void Main(string[] args)
{
    Student std = null;
           
    try
    {
        try
        {
            // following throws NullReferenceException
            std.StudentName = "";
        }
        catch (InvalidOperationException innerEx)
        {
            Console.WriteLine("Inner catch");
        }
    }
    catch
    {
        Console.WriteLine("Outer catch");
    }
}

运行结果:

Outer catch

在上面的例子中,std.StudentName将引发一个NullReferenceException,但是没有任何catch块处理NullReferenceException或Exception类型。 因此,它将由外部catch块处理。

重点
  1. 使用try,catch和finally块来处理C#中的异常。

  2. try块后面必须跟有catch或finally块或两者。

  3. 允许使用不同的异常过滤器的多个catch块。 一般catch {..}块必须最后。

  4. catch {..}和catch(Exception ex){}都不能使用。

  5. finally块必须在try或catch块之后。

  6. finally块将始终执行,而不管是否发生异常。

  7. finally块是释放对象的适当位置。

  8. finally块不能有返回或断点,因为它不允许离开控件。

  9. 在C#中允许嵌套的try-catch块。

  10. 如果找到适当的过滤器,异常将捕获在内部catch块中,否则将被外部catch块捕获。

在下一节中,将了解如何手动生成异常。


版权声明:本站所有教程均为本站原创或翻译,转载请注明出处,请尊重他人劳动果实。请记住本站地址:www.yuanjiaocheng.net (猿教程) 作者:卿文刚
本文标题: C#环境
本文地址:http://www.yuanjiaocheng.net/CSharp/Csharp-hanling-exception.html