HTML5技术

.Net中的AOP系列之《拦截位置》 - tkb至简

字号+ 作者:H5之家 来源:博客园 2016-08-30 18:00 我要评论( )

.Net中的AOP系列之《拦截位置》 本篇目录 本节的源码本人已托管于Coding上:点击查看。 本系列的实验环境:VS 2013 Update 5(建议最好使用集成了Nuget的VS版本,VS Express版也够用),安装了PostSharp。 至今,我们的关注点都是集中在方法上,本节,就看一

.Net中的AOP系列之《拦截位置》

本篇目录



  • 本节的源码本人已托管于Coding上:点击查看。

    本系列的实验环境:VS 2013 Update 5(建议最好使用集成了Nuget的VS版本,VS Express版也够用),安装了PostSharp。

    至今,我们的关注点都是集中在方法上,本节,就看一下位置,这里的位置指的是字段或属性。位置拦截是AOP框架不太通用的功能,因此,本节大多数的例子都是使用支持位置的PostSharp框架,此外,这节还会看到一个特殊的AOP工具(与常见的AOP框架截然不同),叫做PropertyChanged.Fody。

    位置拦截

    也许很多人没有听过C#中有位置这一说,其实,一个字段或者一个属性都是一个位置。字段和属性是OOP中常见的东西,它们为类提供数据和结构。下面简单复习一下,觉得没问题的同学可以直接跳过,记住:属性只是getter/setter方法的语法糖。

    .Net中的字段和属性

    字段是类的成员。它们可以声明为public,private,protected,internal等等,这样就可以限制访问级别了(默认是private)。

    通常,如果封装很重要的话,就不会使用public字段,因此,字段通常被设置成private,然后通过访问器方法在类外面使用该字段。如果有一个private的_balance(余额)字段,那么只能通过其它对象调用Deposit(存款)或者Withdrawal(取款)方法来改变这个字段的值:

    public class BankAccount { decimal _balance; public void SetBalance(decimal amount) { _balance = amount; } public decimal GetBalance(decimal amount) { return _balance; } }

    在C#中,我们可以使用属性语法(get 和set )来减少代码量,下面的代码中,Balance属性封装了一个私有字段_balance:

    public class BankAccount { decimal _balance; public decimal Balance { get { return _balance; } set { _balance = value; } } }

    get 和set都是可选的:如果不需要设置一个字段的值,那么就不需要写setter,getter同样如此。但是,这后面,.Net编译器帮我们创建了方法,如果使用反编译工具如ILSpy看一下IL代码,就会发现编译器创建了一个decimal get_Balance()方法和一个void set_Balance(decimal)方法:

    .class public auto ansi beforefieldinit MyBankingProject.BankAccount extends [mscorlib]System.Object { .field private valuetype [mscorlib]System.Decimal _balance .method public hidebysig specialname instance valuetype [mscorlib]System.Decimal get_Balance () cil managed { //此处省略若干IL代码 } .method public hidebysig specialname instance void set_Balance ( valuetype [mscorlib]System.Decimal 'value' ) cil managed { //此处省略若干IL代码 } }

    自动属性是在C#2.0中引入的,这个工具让语法糖变得更甜了,我们甚至不需要显式创建字段就可以创建一个属性,如下:

    public class MyClass { public string MyProperty {get; set;} }

    当使用自动属性时,必须同时使用get和set,但是可以使用不同的访问级别。比如,get可以设置成公共的,set可以设置成私有的。
    对于我们.Net开发者来说,这并不是什么新鲜事儿,因为我们几乎每天都会使用这些,但是越是最常用的东西,通常你也认为最理所当然,因此,在深入涉及位置拦截的AOP代码之前有必要重温一下细节问题。

    PostSharp位置拦截

    之前的教程我们知道了,AOP工具可以拦截方法,那么从上面我们又知道,属性的底层就是方法,因此,我们可以猜想可以在属性上使用方法拦截切面。事实上这是可行的,可以使用PostSharp或Castle DynamicProxy在属性上创建方法拦截。下面就是一个使用PostSharp在属性上创建方法拦截的控制台例子:

    public class TestClass { public string TestProperty { get; [MyMethodAspect] set;//在一个属性的setter上使用方法拦截切面 } } [Serializable] public class MyMethodAspect:MethodInterceptionAspect { public override void OnInvoke(MethodInterceptionArgs args) { Console.WriteLine("这条语句来自自定义方法拦截切面"); args.Proceed(); } } class Program { static void Main(string[] args) { var test=new TestClass(); test.TestProperty = "测试属性";//这里会调用属性的setter方法 Console.Read(); } }

    效果如下:

    但是这样使用有几个问题:

  • 笨拙。可能必须写两个切面,一个给setter,一个给getter。
  • 只能给属性使用切面,字段的底层不是方法,所以行不通。
  • 没关系,PostSharp给我们提供了一个更方便的方法,只需要写一个类就可以处理getting和setting,还允许为字段和属性编写切面。这就是PostSharp中的LocationInterceptionAspect,下面的例子和上面的一样,只是这次使用了LocationInterceptionAspect:

    [Serializable] public class MyLocationAspect:LocationInterceptionAspect { public override void OnGetValue(LocationInterceptionArgs args) { Console.WriteLine("这条语句来自位置拦截的{0}方法",MethodBase.GetCurrentMethod()); args.ProceedGetValue(); } public override void OnSetValue(LocationInterceptionArgs args) { Console.WriteLine("这条语句来自位置拦截的{0}方法", MethodBase.GetCurrentMethod()); args.ProceedSetValue(); } } public class TestClass2 { [MyLocationAspect] public string TestProperty { get; set; } } static void Main(string[] args) { //var test=new TestClass(); //test.TestProperty = "测试属性"; var test2=new TestClass2(); test2.TestProperty = "位置拦截测试"; Console.WriteLine(test2.TestProperty); Console.Read(); }

    Main方法中,先是给属性赋值,所以会被MyLocationAspect的OnSetValue方法拦截到,然后打印test2.TestProperty时会被OnGetValule方法拦截,因此运行结果如下:

    这里新出现的args.ProceedSetValue();和args.ProceedGetValue();和之前的args.Proceed();是一样的道理,是继续执行属性方法(属性的本质就是方法)的意思。

    真实案例——懒加载

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • 升讯威微信营销系统开发实践:(3)中控服务器的设计 .Net 还是 Java? - sheng.chao

      升讯威微信营销系统开发实践:(3)中控服务器的设计 .Net 还是 Java

      2016-08-26 16:00

    • 开源:ASP.NET MVC+EF6+Bootstrap开发框架 - NFine

      开源:ASP.NET MVC+EF6+Bootstrap开发框架 - NFine

      2016-08-24 11:00

    • ASP.NET 关于GridView 表格重复列合并 - 小飞飞oo

      ASP.NET 关于GridView 表格重复列合并 - 小飞飞oo

      2016-08-23 10:02

    • 拥抱.NET Core,如何开发一个跨平台类库 (1) - KAnts

      拥抱.NET Core,如何开发一个跨平台类库 (1) - KAnts

      2016-08-08 14:00

    网友点评
    '