关于.NET相当处理的构思

 
 年关走近,整个人曾经远非了劳作和创作的豪情,猜想这一个时候很五人跟自家基本上,该相亲的亲近,该聚会喝酒的聚首喝酒,总而言之就是从未了工作的心劲(我有不少想法,但就是叫不动我的小动作,所以我只可以看着人家在做自己想做的事,吃自己想吃的事物。)。本人由上个月的每一周二五篇,到现行的稿子减弱到每礼拜二篇,说个实话,现在的一篇也有不想写的意念了(这一篇仍旧咬着牙写的,感觉实在是写不动了,写博客太折腾人了,何人写何人知道啊!),可是依旧希望写出来可以帮到我们,如有写的供不应求的地点,还望大家多多指正,知识在于总计和反省,对旁人也对团结都是一个加强。
 

   
年关将至,对于大部分程序员来说,登时就足以闲下来一段时间了,不过在这么些闲暇的时日里,只有争执哪门语言更好可以消磨时光,臆想如今会有诸多关于java与.net的博文现身,我代表要作为一个吃瓜群众,静静的看着大佬们发布心境。

 
 这里先来一段废话,缓和一下气氛,免得让我们很难堪(太直白了或者不太好,总不可以见到喜欢的女孩子就表白吧,还得多多的相处,令人以为你沉稳有深度。),现在进来咱们前日的博客内容,这就是.NET的参数用法。因为在.NET的参数用法和约束特别多,对于广大初学者的话,这样充分多彩的参数用户简直就是跟扯淡一样,就算对于是有所丰裕经验的开发者来说,也不至于可以很轻松使用所有的参数用法和甄选适合的参数类型。谈到参数,预计很四个人就只是想着大家在形似的不二法门调用中选用的那么,如string,int,object等等类型,更多的也就从不了记念,就是明亮,也就是在境遇了再去查看一下,这样实在也没错,毕竟不可能话费过多的时日用在什么不常用的知识上,但是自己个人觉得对于文化依旧需要超前有一个到家的求学,可能实际的细节不可以很好的握住,不过对于全局的定义仍旧得有一个整机的读书。

    以上的废话说的够多了,这里就不再赘述了,如故切入核心吧。

 
 下面就简单的介绍一下.NET的有些常用参数用法,如有不足还望指正,也欢迎我们在上边留言啄磨,分享温馨的观点。

   
在品种开发中,对于系统和代码的祥和和容错性都是有对应的要求。实际支出项目中的代码与样例代码的区别,更多的是在代码的运行的安定团结、容错性、扩大性的相比。因为对此实现一个效应来说,实现效益的主导代码是一律的,可能只是在写法上优化而已,可是在贯彻某一个操作上接纳的类来说,那点是绝大多数时候是平等的。这样看来,我们在实际上开支的长河中,需要考虑的题材相比多,已经不仅仅局限于某一有血有肉的效能实现,更多的是代码的康乐和扩张性考虑。

一.DotNet参数概述:

   
.NET中参数(情势参数)变量是艺术或索引器讲明的一局部,而实参是调用方法或索引器时采取的表明式。

   
在CLR中,默认的动静下拥有的措施参数都是传值的。在传递引用类型的目标时,对一个对象的引用会传递给艺术。这里的船引用我是以传值的格局传给方法的。这也意味着方法可以修改对象,而调用者能看到这么些改动。对于值类型的实例,传给方法的实例的一个副本。意味着方法将拿到它专用的一个值类型实例副本,调用者中的实例不受影响。

   
在CLR中允许以传引用而非传值的不二法门传送参数,在C#中运用out和ref来兑现传递引用的法子传值。在C#中使用out和ref来兑现传递引用的章程传值,那五个首要字告诉编译器生成元数据来指明该参数是传引用的,编译器将转移代码来传递参数的地点,而不是传递参数本身。为值类型使用out和ref,效果一样以传值的情势传送引用类型。 
 

    常用的参数重要有中央类型参数,泛型参数,以及<in T>和<out
T>,dynamic等等。例如<in T>和<out
T>,在CLR中协助泛型类型的可变性,C#在4.0时取得了人命泛型遍体所不可不的语法,并且现在编译器也能够领略接口和信托可能的转移。可变性是以一种档次安全的措施,讲一个对象作为另一个对象来利用。可变性应用于泛型接口和泛型委托的门类参数中。协变形用于向调用者重临某项操作的值;逆变性是指调用者想API传入值;不变性是周旋于协变性和逆变性,是指什么也不会生出。对于这下面的学问特其它丰盛,有趣味的能够自行了然,这里就不做详细的牵线了。dynamic类型,C#是一门静态类型的语言,在好几境况下,C#编译器要寻找特定的称呼而不是接口。dynamic可以在编译时做任何事,到实践时再由框架举行拍卖。有关动态类型的介绍也不做更深远的牵线。

   
在.NET中参数的应用方法紧要为可选参数、命名参数、可变多少参数等等。本文下边也是重大介绍这二种参数的施用方法。

   
以上是在骨子里付出中需要直面的问题,笔者在近期的博文中,也在设想这些那么些到底需要怎么去写,以及特别到底需要怎么去领略,在博文中,也有无数的园友对那些的写法和处理提议了协调的理念,在此地自己就写一下要好的一部显明了,可能写的可比浅显和精炼,然则只当是一个引子,可以引出大佬们来谈谈自己的实际项目经验。希望对我们有一个帮忙,也欢迎大家指出自己的想法和看法,分享自己的学识和看法。

二.DotNet参数用法:

   
以下是任重而道远介绍二种参数的用法:可选参数;命名实参;传递可变多少的参数。
  

一.DotNET分外的概述:

   
谈到特别,大家就需要掌握什么叫做分外,万事万物如若我们想去学习,就活该领悟我们要上学的东西是何等,这样在心中同意有一个大约的体味。万分是指成员没有完成它的称谓宣称可以成功的走动。在.NET中,构造器、获取和安装属性、添加和删除事件、调用操作符重载和调用转换操作符等等都没有办法回去错误代码,不过在这多少个社团中又需要报告错误,这就非得提供异常处理体制。

   
在分外的处理中,我们通常拔取到的六个块分别是:try块;catch块;finally块。这多少个块可以联手行使,也足以不写catch块使用,相当处理块可以嵌套使用,具体的主意在底下会介绍到。

   
在充足的处理体制中,一般有两种采纳:重新抛出一致的不得了,向调用栈高一层的代码通知该特此外发出;抛出一个两样的非凡,想调用栈高一层代码提供更增长的特别信息;让线程从catch块的底层退出。 
 

   有关非常的处理格局,有一对指点性的指出。

   1.可选参数:

     (1).基本用法:

       
假设某个操作需要多少个值,而有些值在每一趟调用的时候又频繁是一样的,这时通常可以使用可选参数。在C#往日实现可变参数的功效,往往表明一个涵盖所有可能参数的措施,其他措施调用这么些措施,并传递恰当的默认值。

       
在可选参数中,设计一个主意的参数时,可以为部分或任何参数分配默认值。在调用这些艺术代码可以采取不点名部分实参,接受默认值。还足以在调用方法时,仍可以透过点名参数名称的章程为其传递实参。如下实例:

        static void OptionalParameters(int x, int y = 10, int z = 20)
        {
            Console.WriteLine("x={0} y={1} z={2}",x,y,z);
        }

         OptionalParameters(1, 2, 3);
         OptionalParameters(1, 2);
         OptionalParameters(1);

     以上的例证可以很明亮的看出其用法,int y=10和int
z=20这五个参数就是可选参数。可选参数的运用中,如若调用时大概了一个参数,C#编译器会自行嵌入参数的默认值。向方法传递实参时,编译器按从左向右的顺序对实参举行求值。使用已命名的参数传递实参时,编译器依旧听从从左到右的逐一对实参进行求值。

      (2).基本尺度:

       可选参数包含部分专业,具体的有些渴求如下:

    (a).所有可选参数必须出现在必要参数之后,参数数组(使用params修饰符注解)除外,但他俩必须出现在参数列表的末段,在她们前面是可选参数。

    (b).参数数组无法宣称为可选的,即便调用者没有点名值,将利用空数组代替。

    (c).可选参数无法动用ref和out修饰符。

    (d).可选参数能够为任何项目,但对此指定的默认值却有一些范围,这就是默认值必须为常量(数字或字符串字面量、null、const成员、枚举成员、default(T)操作符)。

    (e).指定的值会隐式转换为参数类型,但是这种转移不可能是用户定义的。

    (f).可以为艺术、构造器、有参属性的参数指定默认值,还足以为属于委托定一些的参数指定默认值。

    (g).C#不同意省略逗号之间的实参。

     
在接纳可选参数时,对于引用类型应用null来做默认值,假设参数类型是值类型,只需要利用相应的可空值类型作为默认值。

      (3).代码示例:

        /// <summary>
        /// 提取异常及其内部异常堆栈跟踪
        /// </summary>
        /// <param name="exception">提取的例外</param>
        /// <param name="lastStackTrace">最后提取的堆栈跟踪(对于递归), String.Empty or null</param>
        /// <param name="exCount">提取的堆栈数(对于递归)</param>
        /// <returns>Syste.String</returns>
        public static string ExtractAllStackTrace(this Exception exception, string lastStackTrace = null, int exCount = 1)
        {
            while (true)
            {
                var ex = exception;
                const string entryFormat = "#{0}: {1}\r\n{2}";
                lastStackTrace = lastStackTrace ?? string.Empty;
                lastStackTrace += string.Format(entryFormat, exCount, ex.Message, ex.StackTrace);
                if (exception.Data.Count > 0)
                {
                    lastStackTrace += "\r\n    Data: ";
                    lastStackTrace = exception.Data.Cast<DictionaryEntry>().Aggregate(lastStackTrace, (current, entry) => current + $"\r\n\t{entry.Key}: {exception.Data[entry.Key]}");
                }
                //递归添加内部异常
                if ((ex = ex.InnerException) == null) return lastStackTrace;
                exception = ex;
                lastStackTrace = $"{lastStackTrace}\r\n\r\n";
                exCount = ++exCount;
            }
        }

       1.适龄的应用finally块:

         
 finally块能够保证不管线程抛出哪些品种的百般都可以被执行,finall块一般用来做清理那多少个曾经成功启动的操作,然后再回去调用者或者finally块之后的代码。

   2.命名实参:

       
 以上讲解了可选参数的局部基本概念和用法,接下去看一下命名参数的相干操功效法:

      (1).基本用法:

         
命名实参是指在指定实参的值时,可以同时指定相应的参数名称。编译器将判断参数的名目是否科学,并将指定的值赋给这一个参数。命名参数在一一实参此前增长它们的参数名称以及一个冒号。如下代码:

new StreamWriter(path:filename,aooend:true,encoding:realEncoding);

 假如要对包含ref和out的参数指定名称,需要将ref和out修饰符放在名称从此,实参此前。

int number;
bool success=int.TryParse("10",result:out number);

      (2).基本尺度:

       
在命名参数中,所有的命名参数必须放在地方实参之后,两者之间的职务无法改变。地点实参总是指向方法讲明中相应的参数,不能够跳过参数之后,在经过命名相应地方的实参来指定。实参如故按编制顺序求值,尽管这一个顺序有可能会不同于参数的讲明顺序。

       
在一般景色下,可选参数与命名实参会一起配合使用。可选参数会大增适用方法的数目,而命名实参会缩短使用办法的数码。为了检查是否留存一定的适用方法,编译器会采用地点参数的相继构建一个传唱实参的列表,然后对命名实参和剩余的参数举行匹配。假设没有点名某个必备参数,或某个命名实参不能够与剩余的参数相匹配,那么这一个艺术就不是适用的。

     
 命名实参有时能够代替强制转换,来救助编译器举办重载决策。假使情势是从模块的外部调用的,更改参数的默认值是具备隐秘的安危的。可以按名称将实参传给没有默认值的参数,可是编译器要想编译代码,所有要求的实参都无法不传递。

      
在写C#代码与COM对象模型举办互操作时,C#的可选参数和命名参数功用是最好用的,调用一个COM组件时,为了以传引用的主意传递一个实参,C#还允许省略REF/OUT,在嗲用COM组件时,C#务求必须向实参应用OUT.REF关键字。 
  

       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.传递可变多少的参数:

     
在项目支出中,有时我们需要定义一个主意来得到可变多少的参数。可以采用params,params只可以采纳于方法签名中的最后一个参数。params关键字告诉编译器向参数应用System.ParamArrayAttribute的实例。我们切实看一下落实的代码:

[AttributeUsage(AttributeTargets.Parameter, Inherited=true, AllowMultiple=false), ComVisible(true), __DynamicallyInvokable]
public sealed class ParamArrayAttribute : Attribute
{
    // Methods
    [__DynamicallyInvokable]
    public ParamArrayAttribute();
}


[__DynamicallyInvokable]
public ParamArrayAttribute()
{
}

   
 以上的代码可以看来该类继承自Attribute类,对于Attribute类可能不会陌生,这就是概念定制属性的基类,表明ParamArrayAttribute类用于定义定制属性,ParamArrayAttribute类在System命名空间下,ParamArrayAttribute类只有一个构造方法,没有实际的兑现。AttributeUsage也定义了性能的运用形式。

   
C#编译器检测到一个格局调用时,会检讨有着拥有指定名称、同时参数没有行使ParamArrayAttribute的艺术。假诺找到一个分外的艺术,编译器生成调用它所需的代码。假诺编译器没有找到一个匹配的情势,会直接检查选拔ParamArrayAttribute的方法。如若找到一个非凡的法子,编译器会先生成代码来布局一个数组,填充它的元素,再生成代码来调用选定的主意。

   
调用一个参数数量可变的艺术时,会招致一部分附加的属性损失,数组对象必须在对上分红,数组元素必须起始化,而且数组的内存末了必须垃圾回收。

    提供一个办法代码,仅供参考:

        /// <summary>
        /// 字符型二维数组转换成DataTable 
        /// </summary>
        /// <param name="stringDyadicArray"></param>
        /// <param name="messageOut"></param>
        /// <param name="dataTableColumnsName"></param>
        /// <returns></returns>
        public DataTable DyadicArrayToDataTable(string[,] stringDyadicArray, out bool messageOut,
            params object[] dataTableColumnsName)
        {
            if (stringDyadicArray == null)
            {
                throw new ArgumentNullException("stringDyadicArray");
            }
            var returnDataTable = new DataTable();
            if (dataTableColumnsName.Length != stringDyadicArray.GetLength(1))
            {
                messageOut = false;
                return returnDataTable;
            }
            for (var dataTableColumnsCount = 0;dataTableColumnsCount < dataTableColumnsName.Length;dataTableColumnsCount++)
            {
                returnDataTable.Columns.Add(dataTableColumnsName[dataTableColumnsCount].ToString());
            }
            for (var dyadicArrayRow = 0; dyadicArrayRow < stringDyadicArray.GetLength(0); dyadicArrayRow++)
            {
                var addDataRow = returnDataTable.NewRow();
                for (var dyadicArrayColumns = 0; dyadicArrayColumns < stringDyadicArray.GetLength(1);dyadicArrayColumns++)
                {
                    addDataRow[dataTableColumnsName[dyadicArrayColumns].ToString()] = stringDyadicArray[dyadicArrayRow, dyadicArrayColumns];
                }
                returnDataTable.Rows.Add(addDataRow);
            }
            messageOut = true;
            return returnDataTable;
        }

  
以上给出了一个运用可变参数数量以及命名参数的施用样例,完成了将二维字节数组转化为DataTable对象,将数组举办遍历,并将数组写入datatable中,对于整个艺术的逻辑就不做深远介绍,代码相比较的简短。

       3.从异常中回复:

         
 我们在抓获异常后,可以针对的写一些至极恢复生机的代码,能够让程序继续运行。在抓获很是时,需要捕获具体的不得了,丰盛的牵线在如何动静下会抛出相当,并精晓从捕获的非凡类型派生出了那个类型。除非在catch块的终极重新抛出分外,否则不要处理或捕获System.Exception非凡。

三.与参数有关的有的指导原则:

    注解方法的参数类型时,应尽可能指定最弱的项目,最好是接口而不是基类。

   
在设计情势的中坚尺度中,迪米特法则也较最少知识标准化,迪米特法则是指假设五个类不必相互直接通信,那么这六个类就不应当直接的相互功效。假使内部一个类需要调用另一个类的某一个措施的话,可以由其它人转发这一个调用。在类协会的统筹上,每一个类都应有尽可能降低成员的走访权限。类之间的耦合度越弱,越方便复用,一个处在弱耦合的类被涂改,不会对有关系的类造成波及。

   
对于参数的使用中,我们在对参数类型的应用上,依旧需要很密切和认真的去研讨,因为在参数类型的概念上,在肯定程度上影响着大家先后的扩大性和安乐,假如参数类型的牢笼相比较大,对于持续措施的扩充,意义是了不起的。在全路面向对象的言语系统中,一切设计形式都是由“多态”延伸而来,对于接口和嘱托都是在大家面向对象设计中利用过多的,目标较多的是在采纳时扩大参数的约束性。

   
在点子的回来值类型中,重回的品类应该评释为最强的品类,以免受限于特定的类型。

      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(); 
            } 
            }

   
 以上的代码只是在表达一种处理格局。应该让抛出的富有特别都沿着方法的调用栈向上传递,而不是把他们”吞噬“了之后抛出一个新的分外。固然一个连串构造器抛出一个可怜,而且该特别未在项目构造器方法中抓获,CLR就会在里头捕获该特别,并改为抛出一个新的TypeInitialztionException。

二.DotNET非常的常用处理机制:

     
在代码暴发分外后,大家需要去处理那多少个非凡,假若一个那么些没有拿走及时的处理,CLR会终止进程。在非常的处理中,大家可以在一个线程捕获很是,在另一个线程中另行抛出十分。非凡抛出时,CLR会在调用栈中向上查找与抛出的分外类型匹配的catch块。尽管没有此外catch块匹配抛出的百般类型,就发出一个未处理非凡。CLR检测到过程中的任何线程有一个位处理至极,都会截止进程。

     1.非常处理块:

     
 (1).try块:包含代码平时需要履行一些通用的资源清理操作,或者需要从非常中复苏,或者双方都亟需。try块还足以分包也许会抛出异常的代码。一个try块至少有一个涉嫌的catch块或finall块。 
     

     
 (2).catch块:包含的是响应一个卓殊需要履行的代码。catch关键字后的圆括号中的表明式是捕获类型。捕获类型从System.Exception或者其派生类指定。CLR自上而下搜素一个郎才女貌的catch块,所以应该教具体的卓殊放在顶部。一旦CLR找到一个怀有相当捕获类型的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类分析:

       
CLR允许相当抛出任何类型的实例,这里大家介绍一个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 CLR
c#》,这里就不做实际的介绍。

四.总结:

 
 以上在对这一个的牵线中,紧要介绍了CLR的特别处理体制,一些较为通用的相当代码,以及对Exception类的介绍。在其实的类型中,大家一般不要将这个直白抛出给客户,大家在编写程序时,已经考虑程序的容错性,在先后捕获到非凡后,尽量去恢复生机程序,或者将特别消息写入日志,让程序进入错误页。假使出现相比严重的这多少个,最终将分外抛出,终止程序。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图