语言安徽印象——聚散苦匆匆

偶遇

俺们以相似的接口函数开发被,为了安全性,我们都亟待针对传播的参数进行认证,确保参数按照我们所盼之范围输入,如果在限外,如空值,不合乎的品种等等,都该被来十分要错误提示信息。这个参数的求证处理发生多种方式,最为简单的方尽管是采用规则语句针对参数进行判定,这样的判定代码虽然好了解,但比较臃肿,如果对大多独参数、多个条件进行拍卖,那么代码就格外臃肿难以维护了,本篇随笔通过分析几栽不同之参数验证办法,最终利用较为优雅的法门展开拍卖。

安徽主次失去过三糟,但各国一样赖都是来去匆匆。

平凡会确定类型参数是否允许吗空,如果是字符或发长限制,如果是整数可能要看清范围,如果是一对非正规之种比如电话号码,邮件地址等,可能需要利用正则表达式进行判定。参考随笔《C#
中参数验证措施的演化》中文章的牵线,我们针对参数的求证措施发生几栽。

(一)2006年

1、常规方法的参数验证

诚如我们不怕是指向艺术的参数使用规则语句的法门展开判定,如下函数所示。

public bool Register(string name, int age)
{
    if (string.IsNullOrEmpty(name))
    {
        throw new ArgumentException("name should not be empty", "name");
    }
    if (age < 10 || age > 70)
    {
        throw new ArgumentException("the age must between 10 and 70","age");
    }

    //insert into db
}

或者

public void Initialize(string name, int id)
{
    if (string.IsNullOrEmpty(value))
        throw new ArgumentException("name");
    if (id < 0) 
        throw new ArgumentOutOfRangeException("id");
    // Do some work here.
}

一经复杂的参数校验,那么代码就较臃肿

void TheOldFashionWay(int id, IEnumerable<int> col, 
    DayOfWeek day)
{
    if (id < 1)
    {
        throw new ArgumentOutOfRangeException("id", 
            String.Format("id should be greater " +
            "than 0. The actual value is {0}.", id));
    }

    if (col == null)
    {
        throw new ArgumentNullException("col",
            "collection should not be empty");
    }

    if (col.Count() == 0)
    {
        throw new ArgumentException(
            "collection should not be empty", "col");
    }

    if (day >= DayOfWeek.Monday &&
        day <= DayOfWeek.Friday)
    {
        throw new InvalidEnumArgumentException(
            String.Format("day should be between " +
            "Monday and Friday. The actual value " +
            "is {0}.", day));
    }

    // Do method work
}

偶然为便利,会拿参数校验的办法,做一个通用的辅助类进行拍卖,如在我之公用类库里面提供了一个:参数验证的通用校验辅助类
ArgumentValidation,使用如下代码所示。

     public class TranContext:IDisposable   
     {   
         private readonly TranSetting setting=null;   
         private IBuilder builder=null;   
         private ILog log=null;   
         private ManuSetting section=null;   
         public event EndReportEventHandler EndReport;   
         public TranContext()   
         {   
        }   
        public TranContext(TranSetting setting)   
        {   
            ArgumentValidation.CheckForNullReference (setting,"TranSetting");   
            this.setting =setting;   
        }   
        public TranContext(string key,string askFileName,string operation)   
        {   
            ArgumentValidation.CheckForEmptyString (key,"key");   
            ArgumentValidation.CheckForEmptyString (askFileName,"askFileName");   
            ArgumentValidation.CheckForEmptyString (operation,"operation");   
            setting=new TranSetting (this,key,askFileName,operation);   
        }  

可是这样的计还是不够健全,不够流畅。

那年凡是和男人同团游华东,中间有平等远在景观是逛安徽黄山。那时嘟嘟太小,所以我们是有限口外出,年轻又无需要带儿女,那种痛感永远不见面再次出矣,以后便孩子长大再结伴出行,我们为不再年轻。

2、基于第三正类库的征办法

在GitHub上发生有说明类库也提供了针对性参数验证的功能,使用起来比较便捷,采用同一栽流畅的串联写法。如CuttingEdge.Conditions齐。CuttingEdge.Condition
里面的例证代码我们来瞧。

public ICollection GetData(Nullable<int> id, string xml, IEnumerable<int> col)
{
    // Check all preconditions:
    Condition.Requires(id, "id")
        .IsNotNull()          // throws ArgumentNullException on failure
        .IsInRange(1, 999)    // ArgumentOutOfRangeException on failure
        .IsNotEqualTo(128);   // throws ArgumentException on failure

    Condition.Requires(xml, "xml")
        .StartsWith("<data>") // throws ArgumentException on failure
        .EndsWith("</data>") // throws ArgumentException on failure
        .Evaluate(xml.Contains("abc") || xml.Contains("cba")); // arg ex

    Condition.Requires(col, "col")
        .IsNotNull()          // throws ArgumentNullException on failure
        .IsEmpty()            // throws ArgumentException on failure
        .Evaluate(c => c.Contains(id.Value) || c.Contains(0)); // arg ex

    // Do some work

    // Example: Call a method that should not return null
    object result = BuildResults(xml, col);

    // Check all postconditions:
    Condition.Ensures(result, "result")
        .IsOfType(typeof(ICollection)); // throws PostconditionException on failure

    return (ICollection)result;
}

public static int[] Multiply(int[] left, int[] right)
{
    Condition.Requires(left, "left").IsNotNull();

    // You can add an optional description to each check
    Condition.Requires(right, "right")
        .IsNotNull()
        .HasLength(left.Length, "left and right should have the same length");

    // Do multiplication
}

这种题道较流畅,而且也供了于强硬的参数校验方式,除了可应用其IsNotNull、IsEmpty等内置函数,也得采用Evaluate这个扩展判断好好之函数来处理部分从定义的判定,应该说可满足绝大多数底参数验证要求了,唯一不好的哪怕是要运用是第三正值类库吧,有时候如果需扩大就麻烦一些。而且貌似的话我们团结一心发生一部分公用类库,如果对参数验证也尚需引入一个类库,还是比费心一些之(个人见解)

 

下午我们不怕停在了黄山即,老公对茶叶感兴趣,我本着友好不打听之事物好奇,所以我们就是顶地面的茶园找茶农了解关于茶叶的种植、生长、采摘以及加工情况,语言稍微有障碍,但并于划带猜,还是学到了很多知识。晚上,在同一下小卖店本想置点生活必需品,却出乎意料之觉察在那么家的墙角立着好几麻木不仁袋茶叶,是正宗的毛尖。那时好像还不曾网购,我们仅留下任何几上的日用,其余钱老数打了茶。那些茶叶塞满了区区个对肩包中的一个,我们比如说扛大山一样直接坐回内蒙古,真是像吃到台同样开心。后来真能淘宝了,出去反倒异常少打当地的土产了,旅程中吗丢失了部分奇怪之大悲大喜。

3、Code Contract

Code
Contracts 是微软研究院开发之一个编程类库,我尽早盼是于C#
In
Depth 的老二版本受,当时.NET
4.0还并未出来,当时凡作一个叔在类库存在的,到了.NET
4.0以后,已经入到了.NET BCL中,该类存在于System.Diagnostics.Contracts
这个命名空间被。

本条是美其名曰:契约编程

 C#代码契约起源于微软开发的一律宗研究语言Spec#(参见http://mng.bz/4147)。

    •
契约工具:包括:ccrewrite(二迈入制重写器,基于项目的装确保契约得以落实实施)、ccrefgen(它生成契约引用集,为客户端提供契约信息)、cccheck(静态检查器,确保代码能以编译时满足要求,而不是独自检查在推行时实际会发出什么)、ccdocgen(它可以为代码中指定的契约生成xml文档)。

    • 契约种类:前置条件、后置条件、固定条件、断言和苟、旧式契约。

      •
代码契约工具下载和安装:下载地址Http://mng.bz/cn2k。(代码契约工具并无包含在Visual
Studio 2010备受,但是那主干类型位于mscorlib内。)

    • 命名空间:System.Diagnostics.Contracts.Contract

Code Contract 使得.NET
中契约式设计与编程变得尤其爱,Contract中之这些静态方法方法包括

  1. Requires:函数入口处必须满足的法
  2. Ensures:函数出口处必须满足的规则
  3. Invariants:所有成员函数出口处都必须满足的原则
  4. Assertions:在某个同点必须满足的尺码
  5. Assumptions:在有平碰得满足的格,用来压缩非必要的告诫信息

Code Contract
的应用文档您得起官网下载交。为了方便使用Visual
Studio开发。我们得设置一个Code Contracts for
.NET 插件。安装了了后头,点击Visual
Studio中的色性质,可以看来如下丰富的选取项:

语言 1

Contract和Debug.Assert有些地方相似:

  1. 还提供了运行时支持:这些Contracts都是足以于周转的,并且使条件不为满足,会弹出类似Assert的同等的对话框报错,如下:
  2. 犹足以以自由的以代码中关闭打开。

而是Contract有再多与更强硬的成效:

  1. Contracts的打算更加分明,通过不同之Requires/Ensures等等调用,代表不同档次的尺度,比只有的Assert更爱懂以及拓展自动分析
  2. Contracts的职更统一,将3种植不同条件都位居代码的开始处于,而非散见于函数的发端和终极,便于寻找和剖析。
  3. 差的开发人员、不同之小组、不同的合作社、不同之库或者都见面发出投机的Assert,这就是大大加了自行分析的难度,也非便宜开发人员编写代码。而Contracts直接被.NET
    4.0支撑,是合的。
  4. 其提供了静态分析支持,这个我们可以通过配备面板看到,通过静态分析Contracts,静态分析工具得以比便于控制函数的各种关于消息,甚至可当Intellisense

Contract中包含了三个器:

  • ccrewrite, 通过奔程序集中把如二进制数据,来支持运行时检测
  • cccheck, 运行时检测
  • ccdoc, 将Contract自动生成XML文档

搭条件的处理,如代码所示。

       /// <summary>
        /// 实现“前置条件”的代码契约
        /// </summary>
        /// <param name="text">Input</param>
        /// <returns>Output</returns>
        public static int CountWhiteSpace(string text)
        {
            // 命名空间:using System.Diagnostics.Contracts;
            Contract.Requires<ArgumentNullException>(text != null, "Paramter:text");// 使用了泛型形式的Requires
            return text.Count(char.IsWhiteSpace);
        }

后置条件(postcondition):表示对章程输出的约:返回值、out或ref参数的价值,以及另外被移之状态。Ensures();

        /// <summary>
        /// 实现“后置条件”的代码契约
        /// </summary>
        /// <param name="text">Input</param>
        /// <returns>Output</returns>
        public static int CountWhiteSpace(string text)
        {
            // 命名空间:using System.Diagnostics.Contracts;
            Contract.Requires<ArgumentNullException>(!string.IsNullOrEmpty(text), "text"); // 使用了泛型形式的Requires
            Contract.Ensures(Contract.Result<int>() > 0); // 1.方法在return之前,所有的契约都要在真正执行方法之前(Assert和Assume除外,下面会介绍)。
                                                          // 2.实际上Result<int>()仅仅是编译器知道的”占位符“:在使用的时候工具知道它代表了”我们将得到那个返回值“。
            return text.Count(char.IsWhiteSpace);
        }

        public static bool TryParsePreserveValue(string text, ref int value)
        {
            Contract.Ensures(Contract.Result<bool>() || Contract.OldValue(value) == Contract.ValueAtReturn(out value)); // 此结果表达式是无法证明真伪的。
            return int.TryParse(text, out value); // 所以此处在编译前就会提示错误信息:Code Contract:ensures unproven: XXXXX
        }

以此代码契约功能比较强硬,不过好像对简易的参数校验,引入这么一个器械感觉麻烦,也不翼而飞开发人员用之起差不多大面积,而且还需要提前安装一个器:Code
Contracts for
.NET。

故此我为非赞同于采取此插件的物,因为代码要交给客户使用,要求客户安装一个插件,并且打开相关的代码契约设置,还是于麻烦,如果没打开,也非会见报告客户代码编译出错,只是会见以运行的时候不校验方法参数。

 

第二龙爬山,导游限制了时空,建议坐缆车上去自己爬下来。可是我们一干人等选了温馨爬上来还攀下去,奇松、怪石、云海,途中的美景足以被丁忘却疲劳。何况要有的发出故事的石头。尤其是见到“飞来石”激动了深漫长,这块石头因为在87本《红楼梦》火了同一把,演了那块上上不成为的顽石后,真即成了一个神话,围观的丁多。还有一样片手机石,因酷似当时的无绳电话机要得叫,当手机现状改变后,石头还是原本的外貌,不了解现在导游怎么附会。

4、使用内置的公用类库处理

基于CuttingEdge.Conditions
的法门,其实我们吧得开一个接近这样的流畅性写法的校验处理,而且不需要那么烦引入第三在类库。

譬如说我们在公用类库里面长一个类库,如下代码所示。

    /// <summary>
    /// 参数验证帮助类,使用扩展函数实现
    /// </summary>
    /// <example>
    /// eg:
    /// ArgumentCheck.Begin().NotNull(sourceArray, "需要操作的数组").NotNull(addArray, "被添加的数组");
    /// </example>
    public static class ArgumentCheck
    {
        #region Methods

        /// <summary>
        /// 验证初始化
        /// <para>
        /// eg:
        /// ArgumentCheck.Begin().NotNull(sourceArray, "需要操作的数组").NotNull(addArray, "被添加的数组");
        /// </para>
        /// <para>
        /// ArgumentCheck.Begin().NotNullOrEmpty(tableName, "表名").NotNullOrEmpty(primaryKey, "主键");</para>
        /// <para>
        /// ArgumentCheck.Begin().CheckLessThan(percent, "百分比", 100, true);</para>
        /// <para>
        /// ArgumentCheck.Begin().CheckGreaterThan&lt;int&gt;(pageIndex, "页索引", 0, false).CheckGreaterThan&lt;int&gt;(pageSize, "页大小", 0, false);</para>
        /// <para>
        /// ArgumentCheck.Begin().NotNullOrEmpty(filepath, "文件路径").IsFilePath(filepath).NotNullOrEmpty(regexString, "正则表达式");</para>
        /// <para>
        /// ArgumentCheck.Begin().NotNullOrEmpty(libFilePath, "非托管DLL路径").IsFilePath(libFilePath).CheckFileExists(libFilePath);</para>
        /// <para>
        /// ArgumentCheck.Begin().InRange(brightnessValue, 0, 100, "图片亮度值");</para>
        /// <para>
        /// ArgumentCheck.Begin().Check&lt;ArgumentNullException&gt;(() => config.HasFile, "config文件不存在。");</para>
        /// <para>
        /// ArgumentCheck.Begin().NotNull(serialPort, "串口").Check&lt;ArgumentException&gt;(() => serialPort.IsOpen, "串口尚未打开!").NotNull(data, "串口发送数据");
        /// </para>
        /// </summary>
        /// <returns>Validation对象</returns>
        public static Validation Begin()
        {
            return null;
        }

        /// <summary>
        /// 需要验证的正则表达式
        /// </summary>
        /// <param name="validation">Validation</param>
        /// <param name="checkFactory">委托</param>
        /// <param name="argumentName">参数名称</param>
        /// <returns>Validation对象</returns>
        public static Validation Check(this Validation validation, Func<bool> checkFactory, string argumentName)
        {
            return Check<ArgumentException>(validation, checkFactory, string.Format(Resource.ParameterCheck_Match2, argumentName));
        }

        /// <summary>
        /// 自定义参数检查
        /// </summary>
        /// <typeparam name="TException">泛型</typeparam>
        /// <param name="validation">Validation</param>
        /// <param name="checkedFactory">委托</param>
        /// <param name="message">自定义错误消息</param>
        /// <returns>Validation对象</returns>
        public static Validation Check<TException>(this Validation validation, Func<bool> checkedFactory, string message)
        where TException : Exception
        {
            if(checkedFactory())
            {
                return validation ?? new Validation()
                {
                    IsValid = true
                };
            }
            else
            {
                TException _exception = (TException)Activator.CreateInstance(typeof(TException), message);
                throw _exception;
            }
        }
......

地方提供了一个例行的检讨与泛型类型检查的通用方,我们而需要对参数检查,如下代码所示。

ArgumentCheck.Begin().NotNull(sourceArray, "需要操作的数组").NotNull(addArray, "被添加的数组");

假定此NotNull就是咱们根据地方的定义方法进行扩展的函数,如下代码所示。

        /// <summary>
        /// 验证非空
        /// </summary>
        /// <param name="validation">Validation</param>
        /// <param name="data">输入项</param>
        /// <param name="argumentName">参数名称</param>
        /// <returns>Validation对象</returns>
        public static Validation NotNull(this Validation validation, object data, string argumentName)
        {
            return Check<ArgumentNullException>(validation, () => (data != null), string.Format(Resource.ParameterCheck_NotNull, argumentName));
        }

无异于道理我们好扩展更多的自定义检查方,如引入正则表达式的拍卖。

ArgumentCheck.Begin().NotNullOrEmpty(libFilePath, "非托管DLL路径").IsFilePath(libFilePath).CheckFileExists(libFilePath);

它们的扩大函数如下所示。

        /// <summary>
        /// 是否是文件路径
        /// </summary>
        /// <param name="validation">Validation</param>
        /// <param name="data">路径</param>
        /// <returns>Validation对象</returns>
        public static Validation IsFilePath(this Validation validation, string data)
        {
            return Check<ArgumentException>(validation, () => ValidateUtil.IsFilePath(data), string.Format(Resource.ParameterCheck_IsFilePath, data));
        }

        /// <summary>
        /// 检查指定路径的文件必须存在,否则抛出<see cref="FileNotFoundException"/>异常。
        /// </summary>
        /// <param name="validation">Validation</param>
        /// <param name="filePath">文件路径</param>
        /// <exception cref="ArgumentNullException">当文件路径为null时</exception>
        /// <exception cref="FileNotFoundException">当文件路径不存在时</exception>
        /// <returns>Validation对象</returns>
        public static Validation CheckFileExists(this Validation validation, string filePath)
        {
            return Check<FileNotFoundException>(validation, () => File.Exists(filePath), string.Format(Resource.ParameterCheck_FileNotExists, filePath));
        }

我们可以因我们的正则表达式校验,封装更多的函数进行快捷使,如果只要从定义的校验,那么即便以基础的Chek函数即可。

语言 2

测试下代码用,如下所示。

        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            ArgumentCheck.Begin().NotNull(args, "启动参数");
            string test = null;
            ArgumentCheck.Begin().NotNull(test, "测试参数").NotEqual(test, "abc", "test");

是ArgumentCheck作为公用类库的一个接近,因此用起来不待更引入第三着类库,也能落实正常化的校验处理,以及可以扩展自定义之参数校验,同时为是支持流式的题道,非常便利。 

下山的尽头路过同片竹林,本来是自太爱的景物,但曾经是对下肢打颤了,所以注意力一直集中在路上,体会到“上山容易下山难”了。下山后便是和团游的例行项目——购物。不过那次导游安排的专门人性化,购物活动是免费洗脚然后出售缓减疲劳的药品。我劳苦功高之对底下泡在热水还有小姑娘吃用灵药按摩上,感觉好极了。受到优待的脚就挑逗我之大脑指挥手赶快掏钱,想抵抗住那种诱惑真的要命麻烦。但我们的钱购置了茶叶了,所以当小姐把证书递到自手里劝购时,我只能报它本身是内蒙古来之,不认字。她只要读给自家听,我说除了简单的口语太正统的封皮报我也是不晓得的。可怜之儿女白忙乎一集,只能和本身聊一些咱究竟是骑马还是骑车骆驼上学的话题。之后就是匆匆离开了,第一蹩脚安徽的推行终止!

飞来石(网络)

2006年黄山

手机石



(二)2014年

这次安徽底推行依旧是黄山,头等同龙中午至黄山时,和上次未等同的凡,村子成了镇。我就记不清是无是上次失去之深地方了隆重了,还是其它换了一个地方。下午失去矣九龙瀑等几个大的景致,第二上开始爬山。

这次出行,我和嘟嘟以及其他三只同事以及个别的孩子同游。嘟嘟已经长暨爬山可以把自远远摔到后了。但黄山不同于泰山,爬泰山协即使犹如走楼梯,黄山可是真正凶险。上去时为了同一段子缆车,其余自己爬。一路臻自己只好示弱,请嘟嘟扶在上下,否则他距离我的视线,我就胆战心惊了。不过示弱既是如出一辙栽政策也是本人的真实写照,爬至中途我都存疑自己还会不能够下,感慨岁月不饶人。

攀登至中途下了一些大暴雨,山越朦胧了。所有那些与山有关的诗句就起先后摸索来了,有时候我思念:那时那刻,一词“倏忽云烟化杳冥,峰峦随水切丹青”,就比“美得像打一样”更具表现力吗?恐怕得看赏景人的经历及知识储备吧。

第二潮安徽之实施同样焦急,匆忙到丢了嘟嘟的相同管衣物。

2014年黄山



(三)2017年

本年同时平等坏和安徽碰面了,这次是由武汉至合肥,跟着动车在安徽动了同一长长达线。出行为火车时自我那个少白天睡觉,因为舍不得那伙臻之山山水水。隔在车窗往去:山青水绿,紫薇花等偶有开放,点缀以青山绿水之中,宛如绿色的玉镶嵌了彩色的宝石,那景色实在是大动人。何况每一个立已下来还能吃丁想到读过的书写,眼前情景和书中人联系起,得不可开交有些许故事来。

其间同样立是六安,乘务员报名字读“六(Lù)安”,“六安瓜片”我是清楚的,却原来一直读错了文章。拿出手机了解及六安的名始于公元前121年,汉武帝取“六地安全、永不反叛乱”之完全,置六安国,历史悠久。因舜封皋陶于六(Lù),故后世称六安啊皋城。这是个有历史的地方,曾经刀光剑影,如今厦林立,无论如何,我们须感谢自己生之一世。

此行以合肥赴任后,第一目的地就是是中国科技大学。这所中科院直属的高校历史并不久远,但却经历过重大变更。成立之新是在帝都,但69年搬迁到安徽,地位为随着下跌。几个校区零零散散的在在不同地方,我们去矣起名噪一时底豆蔻年华班所当的东校区。校园干净清洁,但无北大清华的霸气,也欠武大的风味,可她跟眼前三所高校一样蜚声中外。孩子辈在此间留恋了深漫长。

一个瓶子带来无限快乐!

老二立自身选择了徽园,因为是地方是安徽底一个缩影。出行前关于安徽的攻略太少,走以徽园只能拄先知道的少数浮泛附会了,大概知道安庆园底“万佛塔”,黄山达之“猴子望月”,滁州园的“醉翁亭”,和州园的“陋室”,以及九华山及之地藏菩萨,其他多不极端懂。不过男女辈对于这些地名显然不绝谢谢兴趣,我们有时唠叨几句知道之“徽雕”“徽砚”“徽商”,也随风飘走了。对于美,这些多不如一个废瓶子有意思。

后来在亳州园的战士身上孩子等开始发表想象力了,好好先把它们底瓶子在战士手里,嘟嘟把他手里一直用的跳绳也送了马上号勇士。徽园是99年为迎接五十格外庆建之,这员有点新兵在这边站了18年未懂得里面发生没有人像这么与他互动过。战士一直咧着嘴巴玩在些许单子女于外前面笑得前仰后合,玩得不乐意去。一直顶花灯初上,园里只有咱一家最后离开。

陋室

孩子跟战士

夜里的列车,离开合肥,第三不成同安徽说再见。每一样坏及安徽之遇到还这么短,但这方土地,让人口痴迷。聚散苦匆匆!

无锡印象——无锡凡只好地方!

青海印象——一路朝向西!

武汉印象(一)在回顾和具体中穿行

武汉印象(二)在历史和学识着穿行

武汉印象(三)读书人一名气长叹!

发表评论

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

网站地图xml地图