• C#中异常使用的注意事项


    C#中异常使用的注意事项

    一:两个立足点

    1:正常控制流程下的代码运行并不会带来问题,只有引发异常才会带来效率问题。

    2:不应将异常机制用于正常控制流中。


    二:需要引发异常的四类情况

    第一类情况是:如果运行代码后,造成内存泄漏、资源不可用或应用程序状态不可恢复,则引发异常。Console这个类中,有很多类似这样的代码: 

    if ((value < 1) || (value > 100))
    {
    throw new ArgumentOutOfRangeException("value", value, Environment.GetResourceString("ArgumentOutOfRange_CursorSize"));
    }

    Console这个类虽然也提供了Tester-Doer模式,让调用者可以有更多的方法来验证输入。但是永远不要保证调用者对你的类有足够的了解,他有可能调用你的任何公开方法,而不会考虑先后顺序;所以应该为这类方法引发一些必要的异常。但是,如果你自己写了一个Student业务类,判断年龄,年龄小于0这样的判断,就不应该引发异常,因为那是一个正常控制流。

    第二类需要引发异常的情况是:在捕获异常的时候,如果需要包装一些更有用的信息,则引发异常。这类异常的引发在UI层特别有用。系统引发的异常所带的Message往往更倾向于技术性的描述,而在UI层,异常的用户很可能是最终用户。如果我们需要将异常的Message信息呈现给最终用户,更好的做法是包装异常,然后引发一个含有友好信息的新异常。

    第三类情况:如果底层异常在高层操作的上下文中没有意义,则可以考虑捕获这些底层异常,并引发新的有意义的异常。如将一个InvalidCastException引发为新的ArgumentException。

    第四类正确引发异常的一个典型的例子就是捕获底层API错误代码,并抛出。Console为我们封装了调用windows api返回的错误代码,而让代码引发一个新的异常。

    三:避免throw中将异常堆栈信息吃掉

    代码应该看起来是这样的:

    代码
    try
    {
    (
    new NestedExceptionSample2()).MethodWithTry2();
    }
    catch (Exception)
    {
    //do something
    throw;
    }

    或者:

    代码
    try
    {
    (
    new NestedExceptionSample2()).MethodWithTry2();
    }
    catch
    {
    //do something
    throw;
    }

    尽量避免像下面这样引发异常:

    catch (Exception err)
    {
    //do something
    throw err;
    }

    直接throw err而不是throw将会重置堆栈信息。

    四:处理未捕获异常和多线程异常

    这在我的另一篇博文中已经论述:异常处理之ThreadException、unhandledException及多线程异常处理


    五:避免在调用栈较低位置记录异常

    最适合进行异常记录和报告的是应用程序的最上层,这通常是UI层。假设存在这样的一个应用程序,它的BLL层,即可能被一个Winform窗口程序调用,也可能被一个控制台应用程序调用,那么如果要在BLL模块向管理员报告异常的时候,你不知该使用MessageBox方法还是Console.Write方法。

    如果异常在调用栈的较低位置被记录或报告,且还存在被包装后重新抛出的情况,这就会让记录重复出现。

    六:推荐总是使用FCL异常

    也即慎用自定义异常。需要自定义异常的理由如下:

    1:方便调试,通过抛出一个我们自己定义的异常类型实例,我们可以使捕获代码精确地知道所发生的事情,并以合适的方式进行恢复。

    2:逻辑包装,自定义异常可包装多个其它异常,然后抛出一个业务异常。 

    3:方便调用者编码,在编写自己的类库或者业务层代码的时候,自定义异常可以让调用方更方便处理业务异常逻辑。如保存数据失败,可以分成两个异常"数据库连接失败。"、"网络异常。" 

    4:引入新异常类,使程序员能够根据异常类在代码中采取不同的操作。

    七:不要再从System.ApplicationExcetipn这个基类派生异常

    微软自己也已经修正这一点,当前的建议是:从System.Exception或其它常见基本异常之一派生异常。事实上,现在如果你在Visual studio中输入Excetion,然后使用快捷键tab,vs会自动给你创建一个继承自System.Exception的自定义异常类

    八:避免在finally撰写无效代码

    需要先提出一个问题,即:是否存在一种打破try-finally执行顺序的情况。答案是:没有(除非应用程序本身因为某些很少出现的特殊情况在try块中退出)。你应该始终认为finally内代码会在方法return之前被执行,哪怕return是在try块中。

    但,需要区分引用类型变量和值类型变量在finally中会导致不同结果。 

    代码
    private static int TestIntReturnInTry()
    {
    int i;
    try
    {
    return i = 1;
    }
    finally
    {
    i
    = 2;
    Console.WriteLine(
    "\t将int结果改为2,finally执行完毕");
    }
    }

    它返回的将是1。代码中,i=2实际上是一段无效代码,如果编译采用Release模式,编译器会直接将i=2删除,它不会为其生成对应的IL代码。

    但是: 

    代码
    static User TestUserReturnInTry()
    {
    User user
    = new User() { Name = "Mike", BirthDay = new DateTime(2010, 1, 1) };
    try
    {
    return user;
    }
    finally
    {
    user.Name
    = "Rose";
    user.BirthDay
    = new DateTime(2010, 2, 2);
    Console.WriteLine(
    "\t将user.Name改为Rose");
    }
    }

    我们会发现,TestUserReturnInTry方法返回的User中,Name的值已经改变为Rose了。

  • 相关阅读:
    C++进阶
    傅雷的一生
    OJ (Online Judge)使用
    详解事件委托
    tween.js是一款可生成平滑动画效果的js动画库。tween.js允许你以平滑的方式修改元素的属性值。它可以通过设置生成各种类似CSS3的动画效果。
    利用tween,使用原生js实现模块回弹动画效果
    JS阻止链接跳转代码
    CSS display 属性
    HTML5 Canvas绘文本动画(使用CSS自定义字体)
    MySQL基础CRUD编程练习题的自我提升(1)
  • 原文地址:https://www.cnblogs.com/luminji/p/1930536.html
Copyright © 2020-2023  润新知