关于.NET异常处理的思考

作者: 立即进入  发布:2019-10-09

    年关将至,对于绝大好些个技师来讲,立即就能够闲下来一段时间了,可是在那些闲暇的时刻里,唯有争辨哪门语言更加好能够消磨时光,推测近期会有非常多关于java与.net的博文出现,小编代表要作为二个吃瓜公众,静静的瞧着大佬们发布心思。

    以上的废话说的够多了,这里就不再赘言了,依旧切入核心吧。

    在品种开垦中,对于系统和代码的平静和容错性都以有对应的必要。实际开采品种中的代码与样例代码的分别,更加多的是在代码的周转的欢快鼓劲、容错性、增加性的相比较。因为对于贯彻三个作用来讲,实现效果与利益的为主代码是同一的,可能只是在写法上优化而已,然而在达成某五个操作上选用的类来讲,那点是大许多时候是同等的。那样看来,大家在实际上支付的进度中,供给思量的主题素材相当多,已经不独有局限于某一切实可行的成效实现,越来越多的是代码的安静和扩充性思考。

    以上是在事实上支出中须求面前碰着的主题材料,笔者在新近的博文中,也在思索那几个那三个到底必要怎么去写,以及那么些到底供给怎么去了解,在博文中,也会有过多的园友对丰硕的写法和拍卖建议了温馨的眼光,在此地笔者就写一下协调的片段知道,大概写的可比浅显和精炼,不过只当是一个引子,能够引出大佬们来研商自身的实际上项目经验。希望对我们有二个援救,也款待大家建议自个儿的主张和眼光,分享温馨的学问和观点。

一.DotNET可怜的概述:

关于.NET异常处理的思考。    聊起拾叁分,大家就须要精晓如何叫做非凡,万事万物若是大家想去学习,就应有理解我们要学习的东西是怎么着,那样在心中同意有七个大约的体会。非凡是指成员未有达成它的称谓宣称能够完毕的走动。在.NET中,构造器、获取和装置属性、增多和删除事件、调用操作符重载和调用调换操作符等等都并未有章程回到错误代码,不过在这么些组织中又须要告诉错误,那就务须提供十三分处理体制。

    在那多少个的拍卖中,大家通常使用到的四个块分别是:try块;catch块;finally块。那多少个块能够一同行使,也足以不写catch块使用,非常管理块能够嵌套使用,具体的法子在下边会介绍到。

    在拾壹分的拍卖体制中,平日有三种选用:重新抛出一致的不行,向调用栈高一层的代码文告该极度的发生;抛出多少个例外的不得了,想调用栈高级中学一年级层代码提供更增进的非常消息;让线程从catch块的平底退出。   

   有关非常的管理格局,有一对教导性的提出。

关于.NET异常处理的思考。       1.确切的采用finally块:

           finally块能够确认保证不管线程抛出什么类型的不得了都得以被实践,finall块一般用来做清理那么些曾经打响运转的操作,然后再回来调用者或然finally块之后的代码。

       2.要命捕捉需适当:

           为啥要适度的捕捉万分呢?如下代码,因为我们无法怎么着非常都去捕捉,在破获至极后,大家须求去管理这个非常,若是大家将持有的不得了都捕捉后,不过尚未预感会发生的非常,大家就不曾艺术去处理那些十分。

         借使应用程序代码抛出二个不行,应用程序的另一端则大概预期要捕捉这些可怜,因而无法写成二个”大小通吃“的那么些块,应该允许该特别在调用栈中向上移动,让应用程序代码针对性地管理这些丰裕。

         在catch块中,能够利用System.Exception捕捉非凡,不过最佳在catch块末尾重新抛出十三分。至于原因在末端会讲课到。

          try
            {
                var hkml = GetRegistryKey(rootKey);
                var subkey = hkml.CreateSubKey(subKey);
                if (subkey != null && keyName != string.Empty)
                    subkey.SetValue(keyName, keyValue, RegistryValueKind.String);
            }
            catch (Exception ex)
            {
                Log4Helper.Error("创建注册表错误" + ex);
                throw new Exception(ex.Message,ex);
            }

       3.从那三个中平复:

           大家在抓获卓殊后,能够本着的写一些相当苏醒的代码,能够让程序继续运维。在抓获格外时,须求捕获具体的非凡,丰硕的支配在怎样意况下会抛出特别,并精晓从捕获的十一分类型派生出了那个类型。除非在catch块的结尾重新抛出十三分,否则不要管理或捕获System.Exception十分。

关于.NET异常处理的思考。      4.维持状态:

          平常处境下,大家实现八个操作还是二个办法时,必要调用多少个法子结合造成,在施行的进程中会出现后面多少个点子成功,后边的艺术发生非常。产生不可恢复生机的格外时回滚部分产生的操作,因为我们必要还原信息,全体我们在捕获万分时,供给捕获全部的充裕音讯。

      5.隐形完结细节来保持合同:

          临时恐怕要求捕捉叁个卓殊并再一次抛出贰个不及的十一分,那样能够保持方法的公约,抛出的心极度类型地应当是三个现实的不胜。看如下代码:

FileStream fs = null;
            try
            {
                fs = FileStream();

            }
            catch (FileNotFoundException e)
            {
          //抛出一个不同的异常,将异常信息包含在其中,并将原来的异常设置为内部异常
                throw new NameNotFoundException();
            }
            catch (IOException e)
            {

               //抛出一个不同的异常,将异常信息包含在其中,并将原来的异常设置为内部异常

             throw new NameNotFoundException(); 
            } 
            finally 
            {
               if (fs != null) 
                { 
               fs.close(); 
            } 
            }

     以上的代码只是在验证一种管理形式。应该让抛出的具有特别都沿着方法的调用栈向上传递,而不是把他们”吞噬“了之后抛出贰个新的相当。假若贰个品类构造器抛出一个特别,何况该非常未在等级次序构造器方法中抓获,CLSportage就能够在里头捕获该特别,并改为抛出八个新的TypeInitialztionException。

二.DotNET卓殊的常用管理体制:

      在代码发生极其后,我们需求去管理这么些丰盛,假若三个非常未有拿走及时的管理,CL福睿斯会终止过程。在十三分的拍卖中,大家能够在二个线程捕获卓殊,在另多少个线程中又一次抛出非常。非凡抛出时,CLHaval会在调用栈中向上查找与抛出的老大类型匹配的catch块。如果未有其余catch块相配抛出的要命类型,就产生三个未处理格外。CL福睿斯检验到进度中的任何线程有二个位管理特别,都会结束过程。

     1.不胜管理块:

       (1).try块:满含代码经常要求实行一些通用的财富清理操作,或许须求从十三分中回复,恐怕双方都亟待。try块还足以富含可能会抛出非常的代码。贰个try块起码有贰个涉及的catch块或finall块。       

       (2).catch块:包含的是响应多个非常必要实践的代码。catch关键字后的圆括号中的表明式是捕获类型。捕获类型从System.Exception只怕其派生类钦命。CL奥迪Q5自上而下搜素一个非凡的catch块,所以应当教具体的不行放在最上部。一旦CLSportage找到叁个富有特别捕获类型的catch块,就能够试行内层全体finally块中的代码,”内层finally“是指抛出十三分的tey块早先,到非常极度的catch块之间的享有finally块。

       使用System.Exception捕捉十分后,可以动用在catch块的终极重新抛出十二分,因为只要我们在捕获Exception分外后,未有及时的处理仍然终止程序,这一非凡只怕对前后相继形成比一点都不小的安全隐患,Exception类是有着非常的基类,能够捕获程序中有着的这些,假如出现相当大的要命,大家尚无当即的管理,形成的标题是宏大的。

       (3).finally块:富含的代码是保障会实践的代码。finally块的享有代码实行完结后,线程退出finally块,试行紧跟在finally块之后的语句。要是不设有finally块,线程将从最后贰个catch块之后的言语开端奉行。

      备注:相当块能够构成和嵌套,对于八个要命块的样例,在此处就不做牵线,非常的嵌套可防止备在拍卖特别的时候再一次现身未管理的不得了,以上那几个就不再赘言。

    2.要命管理实例:

       (1).相当处理扩展方法:
        /// <summary>
        ///  格式化异常消息
        /// </summary>
        /// <param name="e">异常对象</param>
        /// <param name="isHideStackTrace">是否隐藏异常规模信息</param>
        /// <returns>格式化后的异常信息字符串</returns>
        public static string FormatMessage(this Exception e, bool isHideStackTrace = false)
        {
            var sb = new StringBuilder();
            var count = 0;
            var appString = string.Empty;
            while (e != null)
            {
                if (count > 0)
                {
                    appString += "  ";
                }
                sb.AppendLine(string.Format("{0}异常消息:{1}", appString, e.Message));
                sb.AppendLine(string.Format("{0}异常类型:{1}", appString, e.GetType().FullName));
                sb.AppendLine(string.Format("{0}异常方法:{1}", appString, (e.TargetSite == null ? null : e.TargetSite.Name)));
                sb.AppendLine(string.Format("{0}异常源:{1}", appString, e.Source));
                if (!isHideStackTrace && e.StackTrace != null)
                {
                    sb.AppendLine(string.Format("{0}异常堆栈:{1}", appString, e.StackTrace));
                }
                if (e.InnerException != null)
                {
                    sb.AppendLine(string.Format("{0}内部异常:", appString));
                    count++;
                }
                e = e.InnerException;
            }
            return sb.ToString();
        }
     (2).验证十分:
       /// <summary>
        /// 检查字符串是空的或空的,并抛出一个异常
        /// </summary>
        /// <param name="val">值测试</param>
        /// <param name="paramName">参数检查名称</param>
        public static void CheckNullOrEmpty(string val, string paramName)
        {
            if (string.IsNullOrEmpty(val))
                throw new ArgumentNullException(paramName, "Value can't be null or empty");
        }

        /// <summary>
        /// 请检查参数不是空的或空的,并抛出异常
        /// </summary>
        /// <param name="param">检查值</param>
        /// <param name="paramName">参数名称</param>
        public static void CheckNullParam(string param, string paramName)
        {
            if (string.IsNullOrEmpty(param))
                throw new ArgumentNullException(paramName, paramName + " can't be neither null nor empty");
        }

        /// <summary>
        /// 检查参数不是无效,并抛出一个异常
        /// </summary>
        /// <param name="param">检查值</param>
        /// <param name="paramName">参数名称</param>
        public static void CheckNullParam(object param, string paramName)
        {
            if (param == null)
                throw new ArgumentNullException(paramName, paramName + " can't be null");
        }

        /// <summary>
        /// 请检查参数1不同于参数2
        /// </summary>
        /// <param name="param1">值1测试</param>
        /// <param name="param1Name">name of value 1</param>
        /// <param name="param2">value 2 to test</param>
        /// <param name="param2Name">name of vlaue 2</param>
        public static void CheckDifferentsParams(object param1, string param1Name, object param2, string param2Name)
        {
            if (param1 == param2) {
                throw new ArgumentException(param1Name + " can't be the same as " + param2Name,
                    param1Name + " and " + param2Name);
            }
        }

        /// <summary>
        /// 检查一个整数值是正的(0或更大)
        /// </summary>
        /// <param name="val">整数测试</param>
        public static void PositiveValue(int val)
        {
            if (val < 0)
                throw new ArgumentException("The value must be greater than or equal to 0.");
        }
     (3).Try-Catch扩大操作:
        /// <summary>
        ///     对某对象执行指定功能与后续功能,并处理异常情况
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="source">值</param>
        /// <param name="action">要对值执行的主功能代码</param>
        /// <param name="failureAction">catch中的功能代码</param>
        /// <param name="successAction">主功能代码成功后执行的功能代码</param>
        /// <returns>主功能代码是否顺利执行</returns>
        public static bool TryCatch<T>(this T source, Action<T> action, Action<Exception> failureAction,
            Action<T> successAction) where T : class
        {
            bool result;
            try
            {
                action(source);
                successAction(source);
                result = true;
            }
            catch (Exception obj)
            {
                failureAction(obj);
                result = false;
            }
            return result;
        }

        /// <summary>
        ///     对某对象执行指定功能,并处理异常情况
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="source">值</param>
        /// <param name="action">要对值执行的主功能代码</param>
        /// <param name="failureAction">catch中的功能代码</param>
        /// <returns>主功能代码是否顺利执行</returns>
        public static bool TryCatch<T>(this T source, Action<T> action, Action<Exception> failureAction) where T : class
        {
            return source.TryCatch(action,
                failureAction,
                obj => { });
        }

        /// <summary>
        ///     对某对象执行指定功能,并处理异常情况与返回值
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <typeparam name="TResult">返回值类型</typeparam>
        /// <param name="source">值</param>
        /// <param name="func">要对值执行的主功能代码</param>
        /// <param name="failureAction">catch中的功能代码</param>
        /// <param name="successAction">主功能代码成功后执行的功能代码</param>
        /// <returns>功能代码的返回值,如果出现异常,则返回对象类型的默认值</returns>
        public static TResult TryCatch<T, TResult>(this T source, Func<T, TResult> func, Action<Exception> failureAction,
            Action<T> successAction)
            where T : class
        {
            TResult result;
            try
            {
                var u = func(source);
                successAction(source);
                result = u;
            }
            catch (Exception obj)
            {
                failureAction(obj);
                result = default(TResult);
            }
            return result;
        }

        /// <summary>
        ///     对某对象执行指定功能,并处理异常情况与返回值
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <typeparam name="TResult">返回值类型</typeparam>
        /// <param name="source">值</param>
        /// <param name="func">要对值执行的主功能代码</param>
        /// <param name="failureAction">catch中的功能代码</param>
        /// <returns>功能代码的返回值,如果出现异常,则返回对象类型的默认值</returns>
        public static TResult TryCatch<T, TResult>(this T source, Func<T, TResult> func, Action<Exception> failureAction)
            where T : class
        {
            return source.TryCatch(func,
                failureAction,
                obj => { });
        }

     本文未有具体介绍try,catch,finally的选拔,而是交由一些比较通用的情势,主即使形似的开荒者对于多个块的利用都有一个认知,就不再做重新的介绍。

三.DotNET的Exception类分析:

        CLCRUISER允许非常抛出任何类型的实例,这里大家介绍四个System.Exception类:

      1.Message属性:建议抛出非常的原委。

[__DynamicallyInvokable]
public virtual string Message
{
    [__DynamicallyInvokable]
    get
    {
        if (this._message != null)
        {
            return this._message;
        }
        if (this._className == null)
        {
            this._className = this.GetClassName();
        }
        return Environment.GetRuntimeResourceString("Exception_WasThrown", new object[] { this._className });
    }
}

    由以上的代码能够观看,Message只具备get属性,所以message是只读属性。GetClassName()获取十分的类。GetRuntimeResourceString()获取运维时能源字符串。

     2.StackTrace属性:满含抛出拾壹分此前调用过的有所办法的称号和签名。

public static string StackTrace
{
    [SecuritySafeCritical]
    get
    {
        new EnvironmentPermission(PermissionState.Unrestricted).Demand();
        return GetStackTrace(null, true);
    }
}

     EnvironmentPermission()用于境况限制,PermissionState.Unrestricted设置权限状态,GetStackTrace()获取仓库追踪,具体看一下GetStackTrace()的代码。

internal static string GetStackTrace(Exception e, bool needFileInfo)
{
    StackTrace trace;
    if (e == null)
    {
        trace = new StackTrace(needFileInfo);
    }
    else
    {
        trace = new StackTrace(e, needFileInfo);
    }
    return trace.ToString(StackTrace.TraceFormat.Normal);
}

public StackTrace(Exception e, bool fNeedFileInfo)
{
    if (e == null)
    {
        throw new ArgumentNullException("e");
    }
    this.m_iNumOfFrames = 0;
    this.m_iMethodsToSkip = 0;
    this.CaptureStackTrace(0, fNeedFileInfo, null, e);
}

      以上是赚取旅馆追踪办法的具体贯彻,此办法首要顾客调节和测验的时候。

     3.GetBaseException()获取基础非常音讯格局。

[__DynamicallyInvokable]
public virtual Exception GetBaseException()
{
    Exception innerException = this.InnerException;
    Exception exception2 = this;
    while (innerException != null)
    {
        exception2 = innerException;
        innerException = innerException.InnerException;
    }
    return exception2;
}

    InnerException属性是内在非常,那是三个虚方法,在此处被重写。具体看一下InnerException属性。

[__DynamicallyInvokable]
public Exception InnerException
{
    [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    get
    {
        return this._innerException;
    }
}

    4.ToString()将特别新闻格式化。

private string ToString(bool needFileLineInfo, bool needMessage)
{
    string className;
    string str = needMessage ? this.Message : null;
    if ((str == null) || (str.Length <= 0))
    {
        className = this.GetClassName();
    }
    else
    {
        className = this.GetClassName() + ": " + str;
    }
    if (this._innerException != null)
    {
        className = className + " ---> " + this._innerException.ToString(needFileLineInfo, needMessage) + Environment.NewLine + "   " + Environment.GetRuntimeResourceString("Exception_EndOfInnerExceptionStack");
    }
    string stackTrace = this.GetStackTrace(needFileLineInfo);
    if (stackTrace != null)
    {
        className = className + Environment.NewLine + stackTrace;
    }
    return className;
}

     在此方式中,将取得的特别音信进行格式化为字符串,this.GetClassName() 获取分外类的有关新闻。

     以上大家注意到[__DynamicallyInvokable]定制属性,大家看一下切实可行的落到实处代码:

[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public __DynamicallyInvokableAttribute()
{
}

   以上大家入眼注释部分,”图像边界“那性子子的有关音讯,请参见《Via CLWranglerc#》,这里就不做具体的牵线。

四.总结:

   以上在对特别的牵线中,主要介绍了CLLacrosse的百般管理体制,一些较为通用的充足代码,以及对Exception类的介绍。在其实的体系中,我们平常不要将丰裕直白抛出给顾客,大家在编写程序时,已经考虑程序的容错性,在前后相继捕获到不行后,尽量去苏醒程序,或然将非常音讯写入日志,让程序步入错误页。倘若出现相比较严重的拾壹分,最终将不胜抛出,终止程序。

本文由6165金沙总站发布于立即进入,转载请注明出处:关于.NET异常处理的思考

关键词: