.net try catch 异常捕获的正确使用姿式。。

很惭愧,写了好多年的代码, 最基本的try catch 才刚刚会正确的使用,
之前只能说叫会用, 可是用法不正确。
先说说,异常的3种使用方式。 见下面的代码。web

public static int Method1()
        {
            try
            {
                int a=int.Prease("aaaa");
                return Method1_1();
            }
            catch (Exception ex)
            {
                throw;   //方式1, 会丢失本try 代码段内的StackTrace信息
                throw ex;   //方式2 会丢失本try 代码段内的StackTrace信息,包括子函数内的
                throw new Exception(ex); //方式3 新的异常。 会丢失更多。
            }
        }

StackTrace信息 很是重要,可以帮助咱们快速定位到异常所在的代码行,帮咱们快速的诊断问题代码。 在生产环境中的时候,通常是没法直接调试的。 那么捕获异常并记录异常所在的行,(前提是要提供调试库 pdb文件,生成的时候回一块儿自动生成。一块儿复制过去就能够)可以帮助咱们很是快速的定位异常作出判断。。数据库

要想可以正确捕获异常信息中的StackTrace信息,根据上面的代码。3中捕获异常并再次抛出的方式都会丢失一部分StackTrace 信息。丢失最小的要数 方式1, 可是,仍是丢失了,try 代码块内的StackTrace 信息, 不信你能够本身测试一下。svg

那么这里就有问题了。 先后逻辑彷佛是冲突的嘛。
1.不能调试。
2.不能丢失StackTrace信息
3.捕获了信息要写入日志
4.有些代码必须在出现异常的时候执行处理代码,而后还得再抛出异常。例如数据库事物,在出错的时候要把事物回滚。函数

固然,咱们有方法处理这种问题。 那就是在每一层,写一个日志。
例如测试

public static int Method1()
        {
            try
            {
                int a=int.Prease("aaaa");
                return Method1_1();
            }
            catch (Exception ex)
            {
               log.Error(ex); //这里当即写入日志。不会丢失StackTrace信息
               throw ex; //而后直接抛出,后处理。
            }
        }

固然这么干,不是不能够。 可是实际上这样干最大的麻烦是,log对象在每一层都须要, 在每一个对象里面都须要。 log成了标配。。 log日志成了头疼的问题。spa

我记得之前我曾经写过关于异常信息的捕获和处理。 个人建议是
在最外层进行捕获,并写入日志。 中间层和底层不要捕获。
我至今也建议这样写。
这样写,最大的好处是省事。并且也照样能控制异常。调试

那么问题来了。 中间层, 必需要处理的时候怎么弄呢? 例如涉及到数据库关闭, 文件关闭等。 必需要在出异常关闭资源的时候, 代码怎么写呢?
中间层,写了try catch ,无论用方式1,方式2,方式3,都会丢失 StackTrace信息。
不写又不行。。。日志

中间层的最终建议。 code

public static int DBSave()
        {
            DbContext DB =  DBContextHelper.GetLISDbContext();   
            var tran = DB.Database.BeginTransaction();
            var isCommit = false;
            try
            {
                。。。。中间业务逻辑代码
                tran.Commit();
                isCommit = true;
                return true;
            }
             //catch (Exception ex) 不要捕获异常,直接外层捕获,
            finally
            {
                if (isCommit == false)
                {   //若是未能成功提交,也就是中间发生过异常,那么回滚.这样捕获的好处是, 异常信息的StackStace 不会丢,能快速定位到问题代码行
                    tran.Rollback(); 
                } 
                tran.Dispose();
                DB.Dispose();
            }

        }

最外层,的代码xml

try{
    ...调用中间层代码。
}
 catch (LisException hisex)
{ //调用对方系统异常.具体信息放在Message中
    res.Code = "600";
    res.Message = hisex.Message;
    res.ExceptionDetails = hisex.ToString();
    MyLog(CallMethodName, ParameterXml, string.Empty, res);
}
catch (Exception ex)
{   // 系统异常.具体信息放在Message中 
    while (ex.InnerException != null) ex = ex.InnerException; //底层的异常容易排除错误
    res.Code = "500";
    res.Message = ex.Message;
    res.ExceptionDetails = ex.ToString();
    //return ex.ToString();
    MyLog(CallMethodName, ParameterXml, string.Empty,  res);
}

对于最顶层, 通常是每一个按钮都有一个 try catch 最顶层,配好log就能够和方便的进行日志记录了。没必要在每一层都写try catch