hBifTs

山自高兮水自深!當塵霧消散,唯事實留傳.荣辱不惊, 看庭前花开花落; 去留随意, 望天上云展云舒.

导航

使用AOP.NET(NAop)的ContractHandle...

Posted on 2004-06-13 16:09  hbiftsaa  阅读(2126)  评论(2编辑  收藏  举报

现在,Souceforge.net上面的AOP.NET增加了一个DBC(Design by contract)中提到的 前置/后置条件检查的功能.

现在相关的文件和dll可以下载了,地址在http://sourceforge.net/projects/aopnet/

现在要介绍的就是怎么样去使用这个ContractHandle.

先说明一下新增的几个类吧:
命名空间都为: NAop.Aspects.Contract
ContractAttribute :
从Attribute类直接继承,是一个Abstract Class,其中有一个Abstract的Check函数,用于ContractHandle进行统一调用.

MethodContractAttribute : 从ContractAttribute继承,同为Abstract Class,增加了AttributeTargets.Method 属性,使其派生类可以用于Method设置.

ParameterContractAttribute : 从ContractAttribute继承,同为Abstract Class,增加了AttributeTargets.Parameter | AttributeTargets.ReturnValue属性,使其派生类可以用于函数参数和返回值设置.

NotNullAttribute : 从MethodContractAttribute继承.从名字可以看出,是用来决定参数是否为null的.通过其构造函数,可以分别设置某些参数为null/不为null.

ExpectedTypeAttribute : 从ParameterContractAttribute继承. 用于检查实际的参数是否为期望的Type的实例,或是期望Type的子类的实例.

RangeAttribute : 从ParameterContractAttribute继承.用于对参数进行检查的.其中分为4类,分别为:
      1,对Int,即数值型的参数进行检查.可以设置是否在某一范围间/外,是否属于/不属于集合.
      2,对String类型.通过.NET自带的Regex(正则表达示类)来进行检查.可以设置RegexOption.
      3,对Enum枚举型进行检查,可以设置是否属于/不属于某集合.
      4,对其它的类型进行检查.通过设置一个Delegate,将实际的检查交由程序员自己实现..

RangeIntAttribute ,RangeStringAttribute ,RangeEnumAttribute, RangeOtherAttribute : 从RangeAttribute继承,由于RangeAttribute构造函数太多,通过这些子类进行分类.方便使用.

ContractHandle : 从IAsect 继承,这样就可以直接加入到AspectCollection中,通过AopBaseContext进行调用.
BeforeInvoke/AfterInvoke分别就是在函数调用前/后调用此函数,是由AopBaseContext来调用的.实际调用其函数/参数/返回值上的Attribute,再调用其Check函数,达到检查的目的.

注: 对于上述每个类的构造函数,都有一个参数(bool enable),用于设置是否取消DBC检查.
对于DBC中的Pre/PostCondition,默认情况下面是这样的,对于ref/out参数,是进行Post检查(即函数调用后),其他的参数/返回值,是进行Pre检查(函数调用前).

使用方法:
老样子,先通过AopFactory生成相应的Proxy,生成时的AopAspectCollection中增加上述ContractHandle类的实例.
再在每一个Virtual函数上加相应的Attribute.
运行,就OK了~
参考代码如下:

   public enum EnumItems{
        Item1,
        Item2,
        Item3,
    }

   
public interface IContractSimp{}

   
public class ContractSimp : IContractSimp{
        [Contract.NotNull]
       
public virtual object CreateNew(ContractSimp obj,int i){
           
if( i == 1)
            {
               
return null;
            }
           
return new ContractSimp();
        }

        [NotNull]
       
public virtual void CreateNew(ContractSimp obj1,ref ContractSimp obj2,out ContractSimp obj3)
        {
            obj2
= obj3 = null;
        }

        [Contract.NotNull(
"obj,obj2",NotNullType.ParamInclude)]
       
public virtual void CreateNew( ContractSimp obj,object obj1,string obj2)
        {
        }

        [Contract.NotNull(
"obj,obj2",NotNullType.ParamExclude)]
       
public virtual void CreateNew3( ContractSimp obj,object obj1,string obj2)
        {
        }

       
public virtual void TestForString( [RangeString("http://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?")]string obj1){}

       
public virtual void TestForTypeEquals( [ExpectedType(typeof(IContractSimp),true)] object obj){
        }

       
public virtual void TestForEnumRange( [RangeEnum("Item1,Item3",typeof(EnumItems),RangeType.EnumExclude)] EnumItems item){ }

       
public virtual void TestRangeInt([RangeInt(10,10,RangeType.IntBeyond)] int obj1,[RangeInt("12,48,58",RangeType.IntExclude)]int obj2){}

       
public virtual void TestOtehrRange( [RangeOther(typeof(ContractSimp),"DelegateCheck","123")]object obj){}

       
public static bool DelegateCheck(IAopContext context,int index,string attachinfo){ Console.WriteLine(attachinfo); return false;
        }

    }

   
/// <summary>
   
/// Summary description for TestContract.
   
/// </summary>
   
///
    [TestFixture]
   
public class TestContract
    {
       
private ContractSimp test;

        [SetUp]
public void Setup(){
            AopAspectCollection aspects
= new AopAspectCollection();
            aspects.Add(
new ContractHandle());
            test
= (ContractSimp)AopFactory.Create(typeof(ContractSimp),new object[0],aspects);
        }

        [Test,ExpectedException(
typeof( ReturnNullException))] public void TestCreateNew(){
            test.CreateNew(
new ContractSimp(),1);
        }

        [Test,ExpectedException(
typeof( ArgumentNullException))] public void TestCreateNew1(){
            test.CreateNew(
null,0);
        }

        [Test]
public void TestCreateNew2(){
            test.CreateNew(
new ContractSimp(),null,"tiger");
        }

        [Test]
public void TestCreateNew3(){
            test.CreateNew3(
null,new object(),null);
        }

        [Test,ExpectedException(
typeof(ArgumentNullException))] public void TestCreateNewRef(){
            ContractSimp obj3;
            ContractSimp obj2
= new ContractSimp();
            test.CreateNew(
new ContractSimp(),ref obj2,out obj3);
        }

        [Test,ExpectedException(
typeof( TypeNotMatchException))] public void TestTypeEquals(){
            test.TestForTypeEquals(
new ContractSimp());
            test.TestForTypeEquals(
new object());
        }

        [Test,ExpectedException(
typeof( RangeNotMatchException))] public void TestForEnum(){
            test.TestForEnumRange( EnumItems.Item2);
            test.TestForEnumRange( EnumItems.Item1);
        }

        [Test,ExpectedException(
typeof( RangeNotMatchException))] public void TestForRangeInt(){
            test.TestRangeInt(
10,48);
        }

        [Test,ExpectedException(
typeof( RangeNotMatchException))] public void TestRangeOther(){
            test.TestOtehrRange(
new object());
        }

        [Test]
public void TestRangeString(){
            test.TestForString(
"http://www.sina.com.cn");
        }

    }


注: 其类的名字参考了JGTM的一个评论.在此说明.非常感谢 :P
有什么问题,请与 hBifTs/dudu联系.