C#、契约编程

何为契约式编程?

  契约式编程是在.NET4.0后引入的,它是减少了大型项目成本突破性的技术。契约的思想很简单,它只是一组结果为真的表达式,如若违反契约失效。

契约式编程初探

  需求:用户输入两个数做除法运算。

    步骤一:新建一个类,用作对数字进行运算(Rationator.cs)   

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication8
{
    internal class RationalNumber
    {
        private int numberator,denominator;
        public RationalNumber(int numberator,int denominator)
        {
            this.numberator = numberator;
            this.denominator = denominator;
        }
        public int division
        {
            get
            {
                return denominator / numberator;
            }
        }
    }
}

    步骤二、main方法中编写代码进行相应测试

        static void Main(string[] args)
        {
            Console.Write("Please enter a number(denominator):");
            string denominator = Console.ReadLine();
            Console.Write("Please enter a number(numberator):");
            string numberator = Console.ReadLine();
            if (!denominator.IsNumberic() || !numberator.IsNumberic())
                Console.WriteLine("The value entered is not a numberic value.");
            else
            {
                RationalNumber taionalnumber = new RationalNumber(int.Parse(numberator), int.Parse(denominator));
         Console.WriteLine(taionalnumber.division); } }

   编写扩展方法验证输入的是否是一个数字

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication8
{
    public static class ExtendActions
    {
        public static Boolean IsNumberic(this string value)
        {
            return System.Text.RegularExpressions.Regex.IsMatch(value, @"^[+-]?\d*[.]?\d*$");
        }
    }
}

如上代码不够严谨,虽然做了输入数字判断。但是现实中,分母是不能为0的,通常程序员会这样写

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication8
{
    internal class RationalNumber
    {
        private int numberator,denominator;
        public RationalNumber(int numberator,int denominator)
        {
            if (denominator == 0)
                throw new ArgumentException("The second argument can not be zero.");
            this.numberator = numberator;
            this.denominator = denominator;
        }
        public int division
        {
            get
            {
                return denominator / numberator;
            }
        }
    }
}

那么,我们来看下契约式的写法

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;

namespace ConsoleApplication8
{
    internal class RationalNumber
    {
        private int numberator,denominator;
        public RationalNumber(int numberator,int denominator)
        {
            Contract.Requires(denominator!=0,"The second argument can not be zero.");
            this.numberator = numberator;
            this.denominator = denominator;
        }
        public int division
        {
            get
            {
                return denominator / numberator;
            }
        }
    }
}

        static void Main(string[] args)
        {
            Console.Write("Please enter a number(denominator):");
            string denominator = Console.ReadLine();
            Console.Write("Please enter a number(numberator):");
            string numberator = Console.ReadLine();
            if (!denominator.IsNumberic() || !numberator.IsNumberic())
                Console.WriteLine("The value entered is not a numberic value.");
            else
            {
                try
                {
                    RationalNumber taionalnumber = new RationalNumber(int.Parse(numberator), int.Parse(denominator));
                    Console.WriteLine(taionalnumber.division);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }

PS:    CR + 两下table可以快捷输出 :Contract.Requires

ps:  虽然契约加上了,.NET4.0之后也已经支持契约式编程,但如果想使用Contract方法实现运行时的验证,还需要单独安装一个VS插件。装好之后,去项目属性里开启运行时检查



需要注意的是,如果想要在Debug和Release Build都使用运行时验证功能,则需要在项目设置为Debug和Release编译时,分别设置打开Runtime check。

 

至此,运行项目,能看到和 加 if 判断然后抛异常差不多的效果。

接下来,就探讨一下前置条件是啥。契约中到底有哪些东西。

1. Assert

Assert:断言是最基本的契约,断言失败时CLR仅调用DEBUG.Assert,成功时,什么都不做。

        static void Main(string[] args)
        {
            try
            {
                Console.Write("Please enter a number(denominator):");
                string denominator = Console.ReadLine();
                Contract.Assert(denominator.IsNumberic(), "Enter variable is not a numberic.");
                Console.WriteLine("denominator:{0}",denominator.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

2.Assume

Assume:假设契约,运行时验证检查和Assert一样。

PS:我感觉其实断言契约和假设契约一样,为什么会分成两个,可能就是根据便于程序员理解而已。书面意思:denominator断定它是个数字,denominator假设它是个数字

        static void Main(string[] args)
        {
            try
            {
                Console.Write("Please enter a number(denominator):");
                string denominator = Console.ReadLine();
                Contract.Assume(denominator.IsNumberic(), "Enter variable is not a numberic.");
                Console.WriteLine("denominator:{0}",denominator.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

3.Requires

Requires:前置条件契约,通常用作方法参数的验证,先前已经有过介绍,这里就不阐述了。

4.Ensures

Ensures:后置条件契约,通常用作方法返回值验证。

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;

namespace ConsoleApplication8
{
    internal class RationalNumber
    {
        private int numberator,denominator;
        public RationalNumber(int numberator,int denominator)
        {
            Contract.Requires(denominator != 0, "The second argument can not be zero.");
            this.numberator = numberator;
            this.denominator = denominator;
        }
        public int divisions
        {
            get
            {
                Contract.Ensures(Contract.Result<int>() >2, "return value need to be greater than 2.");
                return denominator / numberator;
            }
        }
    }
}
        static void Main(string[] args)
        {
            Console.Write("Please enter a number(denominator):");
            string denominator = Console.ReadLine();
            Console.Write("Please enter a number(numberator):");
            string numberator = Console.ReadLine();
            if (!denominator.IsNumberic() || !numberator.IsNumberic())
                Console.WriteLine("The value entered is not a numberic value.");
            else
            {
                try
                {
                    RationalNumber taionalnumber = new RationalNumber(int.Parse(numberator), int.Parse(denominator));
                    Console.WriteLine(taionalnumber.divisions);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }

 后置条件契约,有个好处就是返回值不需要用临时变量保存了。如果没有采用契约编程,那么通常我们是这样写的

public int divisions
{
get
{
int result= denominator / numberator;
return result>2?result:0;
}
}

转载于:https://www.cnblogs.com/hucemail/p/5356548.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值