惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
Hacker News: Ask HN
Hacker News: Ask HN
V
Visual Studio Blog
Hugging Face - Blog
Hugging Face - Blog
博客园 - 【当耐特】
I
InfoQ
A
About on SuperTechFans
宝玉的分享
宝玉的分享
Project Zero
Project Zero
C
CXSECURITY Database RSS Feed - CXSecurity.com
量子位
The Register - Security
The Register - Security
大猫的无限游戏
大猫的无限游戏
Blog — PlanetScale
Blog — PlanetScale
Simon Willison's Weblog
Simon Willison's Weblog
C
Cyber Attacks, Cyber Crime and Cyber Security
T
The Exploit Database - CXSecurity.com
Cyberwarzone
Cyberwarzone
L
LINUX DO - 热门话题
博客园 - 聂微东
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
P
Privacy International News Feed
T
Tenable Blog
博客园 - 叶小钗
P
Palo Alto Networks Blog
S
Securelist
F
Full Disclosure
Help Net Security
Help Net Security
爱范儿
爱范儿
Cisco Talos Blog
Cisco Talos Blog
F
Fortinet All Blogs
Google DeepMind News
Google DeepMind News
IT之家
IT之家
S
Secure Thoughts
Martin Fowler
Martin Fowler
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
小众软件
小众软件
G
GRAHAM CLULEY
J
Java Code Geeks
Forbes - Security
Forbes - Security
Application and Cybersecurity Blog
Application and Cybersecurity Blog
A
Arctic Wolf
L
LangChain Blog
Webroot Blog
Webroot Blog
TaoSecurity Blog
TaoSecurity Blog
月光博客
月光博客
T
The Blog of Author Tim Ferriss
Engineering at Meta
Engineering at Meta
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

博客园 - sig556

微信小程序开发需要注意的30个坑 数字证书制作及程序集签名 JAVA和android 环境配置 硬盘安装win2003 MongoDb使用 配置 Win7 和 IIS7 以支持WCF WCF X.509证书验证 IIS+PHP ,apache+Php架设 - sig556 - 博客园 Ubuntu Server学习笔记 FCKeditor 上传自动重命名、按月创建文件夹和基本操作 [转] 软件测试计划模板 web测试的一些经验分享 软件测试流程实施方案 一些常用的正则表达式 - sig556 - 博客园 ASP.net国际化--页面可以选择输出语言 - sig556 - 博客园 项目开发过程文档 SharpZipLib使用示例 需求管理工具DOORS介绍 [转] B/S 系统界面设计规范
PostSharp - Lightweight Aspect-Oriented System
sig556 · 2010-07-03 · via 博客园 - sig556

PostSharp 是一个令人兴奋的项目,他结合了 MSBuild Task 和 MSIL Injection 技术,从另外一个角度实现 AOP 编程。试用过后你会感觉到其便利性,我们和以往基于 Dynamic Proxy 方式的 AOP 解决方案做个比较。

    * 由于采用 MSIL Injection,因此静态代码注入的执行效率要高于使用 Reflection Emit。
    * 使用 MSBuild Task,使得开发人员可以像使用编译器内置 Attribute 那样使用 AOP。
    * 可以拦截任意方法,而 Dynamic Proxy 方式的 AOP 往往采取继承方式来拦截 Virtual 方法。
    * 拥有更多的控制权。包括中断执行流程,修改参数和返回值等等。
    * 还可以拦截 Field Access、Exception 等操作。
    * 无需将对象创建代码改成 "new proxy()",更加透明。
    * 可以使用通配符进行多重拦截匹配。
    * 静态注入带来的问题更多的是注入代码的质量和调试复杂度。

我们写一个简单的例子,看看效果。
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using PostSharp.Laos;

[Serializable]
public class AopMethodAttribute : OnMethodBoundaryAspect
{
  public override void OnEntry(MethodExecutionEventArgs eventArgs)
  {
    // 获取方法名称
    Console.WriteLine("OnEntry:{0}.{1}", eventArgs.Method.ReflectedType, eventArgs.Method);
   
    // 显示方法参数
    ParameterInfo[] ps = eventArgs.Method.GetParameters();
    object[] pv = eventArgs.GetArguments();

    for (int i = 0; i < ps.Length; i++)
    {
      Console.WriteLine(" {0}={1}", ps[i].Name, pv[i]);
    }
  }

  public override void OnExit(MethodExecutionEventArgs eventArgs)
  {
    Console.WriteLine("OnExit...");
  }
}

public class MyClass
{
  [AopMethod]
  public int Test(int i)
  {
    Console.WriteLine("Test:{0}", i);
    return i++;
  }
}

MyClass o = new MyClass();
o.Test(123);

输出:
OnEntry:MyClass.Int32 Test(Int32)
i=123
Test:123
OnExit...

整个过程非常简单:
1. 创建一个继承自 OnMethodBoundaryAspect 的特性类,用于拦截方法。
2. override 特定的方法,执行拦截操作。方法参数提供了各种操作能力。
3. 向目标方法添加特性。
4. 编译,执行。

或许你会好奇,AopMethodAttribute 是如何被创建实例,并被执行的呢?

1. 注意编译时 VS2005 Output 窗口的输出内容,你会看到如下内容。其实 PostSharp 提供了一个 MSBuild Task,在我们每次编译时会调用它执行一些注入操作。
PostSharp 1.0 [1.0.4.162] - Copyright (c) Gael Fraiteur and Community, 2006.

2. 用反编译工具看看注入后的方法内容。看完这些代码,就算我不说,你也能明白它是如何实现拦截的了。
static MyClass()
{
  if (!~PostSharp~Laos~Implementation.initialized)
  {
    throw new LaosNotInitializedException();
  }
  ~PostSharp~Laos~Implementation.~targetMethod~1 = methodof(MyClass.Test);
  ~PostSharp~Laos~Implementation.~aspect~1.RuntimeInitialize(~PostSharp~Laos~Implementation.~targetMethod~1);
}

public int Test(int i)
{
  int returnValue;
  MethodExecutionEventArgs eventArgs;
  try
  {
    object[] arguments = new object[] { i };
    eventArgs = new MethodExecutionEventArgs(methodof(MyClass.Test, MyClass), this, arguments);
    ~PostSharp~Laos~Implementation.~aspect~1.OnEntry(eventArgs);
    if (eventArgs.FlowBehavior == FlowBehavior.Return)
    {
      return (int) eventArgs.ReturnValue;
    }
    Console.WriteLine("Test:{0}", i);
    int num = i++;
    returnValue = num;
    eventArgs.ReturnValue = returnValue;
    ~PostSharp~Laos~Implementation.~aspect~1.OnSuccess(eventArgs);
    returnValue = (int) eventArgs.ReturnValue;
  }
  catch (Exception exception)
  {
    eventArgs.Exception = exception;
    ~PostSharp~Laos~Implementation.~aspect~1.OnException(eventArgs);
    switch (eventArgs.FlowBehavior)
    {
      case FlowBehavior.Continue:
        return returnValue;

      case FlowBehavior.Return:
        return (int) eventArgs.ReturnValue;
    }
    throw;
  }
  finally
  {
    eventArgs.ReturnValue = returnValue;
    ~PostSharp~Laos~Implementation.~aspect~1.OnExit(eventArgs);
    returnValue = (int) eventArgs.ReturnValue;
  }
  return returnValue;
}

我们可以使用通配符拦截更多的内容,以简化我们的编码。
[AopMethod(AttributeTargetMembers="T*")]
public class MyClass
{
  public int T1(int i)
  {
    Console.WriteLine("T1:{0}", i);
    return i++;
  }

  public void T2(string s)
  {
    Console.WriteLine("T2:{0}", s);
  }
}

我们继续写一点其它的例子,诸如拦截属性访问和异常。

Field Aspect
[Serializable]
public class AopPropertyAttribute : OnFieldAccessAspect
{
  public override void OnGetValue(FieldAccessEventArgs eventArgs)
  {
    Console.WriteLine("ExposedFieldValue:{0}; StoredFieldValue:{1}",
      eventArgs.ExposedFieldValue, eventArgs.StoredFieldValue);
  }

  public override void OnSetValue(FieldAccessEventArgs eventArgs)
  {
    Console.WriteLine("ExposedFieldValue:{0}; StoredFieldValue:{1}",
      eventArgs.ExposedFieldValue, eventArgs.StoredFieldValue);
  }
}

public class MyClass
{
  [AopProperty]
  private int x;

  public int X
  {
    get { return x; }
    set { x = value; }
  }
}

Exception Aspect
[Serializable]
public class AopExceptionAttribute : OnExceptionAspect
{
  public override void OnException(MethodExecutionEventArgs eventArgs)
  {
    Console.WriteLine(eventArgs.Exception.Message);
    eventArgs.FlowBehavior = FlowBehavior.Return;
  }
}

public class MyClass
{
  [AopException]
  public void Test(int i)
  {
    throw new Exception("Error...");
  }
}

更详细的信息,请访问 PostSharp 网站,或者查阅其帮助文件。