.net postsharp编译时生成的代码?
使用PostSharp进行AOP框架设计:一个简单的原型
AOP已经不是一个什么新名词了,在博客园使用关键字搜索可以查出n多条关于AOP的介绍,这里就不再赘述了。
在Bruce Zhang's Blog里面有很多关于AOP介绍及其在.net下实现研究,总觉得如果什么都从头来写难免有自造轮子的嫌疑,但是目前也没有很成熟的AOP框架让我们能轻松完成基于AOP架构,不过一直以来都在关注的PostSharp开源项目日趋成熟,目前已发布了PostSharp 1.0 (Beta release 3)。即使如此,也还没能到应用到产品上的时候。
前段时间一直在封装一个权限系统,时常为如何给调用方提供一个良好的编程接口烦恼,加之前前段时间考虑的日志、异常接管、事务、缓存等等一些横向组件的架构分析,自然就想用AOP技术实现,但是由于实现难度实在不小作罢;这两天又重新学习研究了PostSharp的架构与实现思想,觉得还是尝试一下,将其融入现有框架;
早在年初就有不少前辈大师就如何使用这个东西撰写过文章,如Q.yuhen的PostSharp - Lightweight Aspect-Oriented System该仁兄下面见解很到位:
和以往基于 Dynamic Proxy 方式与 AOP 解决方案做个比较。
- 由于采用 MSIL Injection,因此静态代码注入的执行效率要高于使用 Reflection Emit。
- 使用 MSBuild Task,使得开发人员可以像使用编译器内置 Attribute 那样使用 AOP。
- 可以拦截任意方法,而 Dynamic Proxy 方式的 AOP 往往采取继承方式来拦截 Virtual 方法。
- 拥有更多的控制权。包括中断执行流程,修改参数和返回值等等。
- 还可以拦截 Field Access、Exception 等操作。
- 无需将对象创建代码改成 "new proxy()",更加透明。
- 可以使用通配符进行多重拦截匹配。
- 静态注入带来的问题更多的是注入代码的质量和调试复杂度。
另外有一老外的Using AOP and PostSharp to Enhance Your CodeAB两部分,相当精彩,本文就是在参考这两篇好文的基础上做的。
我们假设有这么个场景,其实这也是实际业务中很常见的处理方式:有一定单管理模块,具备新增、删除两功能,我们在新增删除的时候必须校验权限,在删除的时候还必须记录日志,出现异常了还必须捕捉并记录异常;
按以前的写法我们可能很麻烦,我们要如此这般的写:
{
public bool Add(string id, string orderName)
{
try
{
if (User.AddEnable)
{
//TODO:新增订单的实现
Console.WriteLine("正在执行新增订单方法的操作,回车继续……");
Console.ReadLine();
Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);
return true;
}
else
{
//
}
}
catch (Exception)
{
//TODO:记录异常的实现
throw;
}
return true;
}
public bool Delete(string id)
{
try
{
if (User.DeleteEnable)
{
//TODO:删除订单的实现
Console.WriteLine("您删除订单成功:编号:{0}", id);
}
else
{
//
}
}
catch (Exception)
{
//TODO:记录异常的实现
throw;
}
return true;
}
这种写的弊端我就不多说了,有很多先驱都阐述过……
我要演示的是采用AOP技术的框架原型实现:
首先我们应该安装PostSharp(一定要安装要不能没办法注入处理代码)
然后我们实现Orders对象
namespace PostSharp.Demo
{
public class Orders
{
[Permission]
[Exception]
public bool Add(string id, string orderName)
{
Console.WriteLine("正在执行新增订单方法的操作,回车继续……");
Console.ReadLine();
Console.WriteLine("您添加订单成功:编号:{0},名称:{1}", id, orderName);
return true;
}
[Logger]
[Permission]
[Exception]
public bool Delete(string id)
{
Console.WriteLine("您删除订单成功:编号:{0}", id);
return true;
}
}
}
当然还要模拟一个用户资格认证
{
/// <summary>
/// 静态的用户对象,用于存放当前登录用户,成员资格
/// </summary>
public static class User
{
private static string _userId;
public static string UserId
{
get { return _userId; }
set { _userId = value; }
}
public static bool AddEnable
{
get
{
return (_userId.ToLower() == "admin");
}
}
public static bool DeleteEnable
{
get
{
return (_userId.ToLower() == "admin");
}
}
}
}
再然后我们实现权限控制方面PermissionAttribute,日志方面LoggerAttribute,异常处理方面ExceptionAttribute……
PermissionAttribute
using PostSharp.Laos;
namespace PostSharp.Demo
{
[Serializable]
[global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
public class PermissionAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionEventArgs eventArgs)
{
if (!User.AddEnable)
{
Console.WriteLine("用户:【{0}】没有权限:【{1}】", User.UserId, eventArgs.Method);
eventArgs.FlowBehavior = FlowBehavior.Return;
}
}
}
}
LoggerAttribute
using PostSharp.Laos;
namespace PostSharp.Demo
{
[Serializable]
[global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
public sealed class LoggerAttribute : OnMethodInvocationAspect
{
public override void OnInvocation(MethodInvocationEventArgs eventArgs)
{
DateTime time = DateTime.Now;
string log = "时间:{0},操作人员:{1},操作:{2}!";
object[] arg = eventArgs.GetArguments();
log = String.Format(log, time, User.UserId, "删除Id为" + arg[0].ToString() + "的订单!");
System.IO.File.WriteAllText("C:\\Log.Txt", log);
}
}
}
ExceptionAttribute
using PostSharp.Laos;
namespace PostSharp.Demo
{
[Serializable]
[global::System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = false)]
public class ExceptionAttribute : OnExceptionAspect
{
public override void OnException(MethodExecutionEventArgs eventArgs)
{
Console.WriteLine("程序出现异常:{0}", eventArgs.Exception.Message);
eventArgs.FlowBehavior = FlowBehavior.Return;
}
}
}
然后再用控制台程序测试下能不能成功
Console.WriteLine("请输入用户名:");
User.UserId = Console.ReadLine();
Console.WriteLine("请输入密码:");
Console.ReadLine();
string id;
LRedo:
Console.WriteLine("请输入您要执行的操作:新增(A),删除(D),退出(X)");
string opt = Console.ReadLine();
if (opt.ToLower() == "a")
{
Console.WriteLine("请输入订单编号:");
id = Console.ReadLine();
Console.WriteLine("请输入订单名称:");
string name = Console.ReadLine();
order.Add(id, name);
}
else if (opt.ToLower() == "d")
{
Console.WriteLine("请输入订单编号:");
id = Console.ReadLine();
order.Delete(id);
}
else if (opt.ToLower() == "x")
{
}
else
{
Console.WriteLine("您的输入不正确,请重新输入!");
goto LRedo;
}
Console.WriteLine("按任意键退出……");
Console.ReadLine();
写完这些我们再反编译一下生成的exe文件,发现里面的Orders成了这模样了,神奇了?
反编译后的代码代码很简单,我是采用控制台应用实现的,如果您有兴趣,请下载Demo源码玩玩。
.net postsharp编译时生成的代码?
最近下载了postsharp,发现给方法添加[HandleException] attribute后,反编译后自动生成了很多代码,思考了很久,还是不知道在编译该程序集时,怎么生成的,所以希望大家能给与指点。
原类
public class MyClass {
public MyClass() { }
[HandleException]
public int MyMethod(int x, string someString, float anotherFloat, bool theBool)
{
int b = 0;
int a = 5 / b; return x + 1;
}
}
编译后,用ILSPY反编译后生成如下代码:

望 各位大神能给与指点,谢谢。
.net postsharp编译时生成的代码?的更多相关文章
- apt 根据注解,编译时生成代码
apt: @Retention后面的值,设置的为CLASS,说明就是编译时动态处理的.一般这类注解会在编译的时候,根据注解标识,动态生成一些类或者生成一些xml都可以,在运行时期,这类注解是没有的~~ ...
- qmake.exe是在Qt安装编译时生成的,里面内嵌了Qt相关的一些路径(最简单的方法是保持一样的安装路径,最方便的办法是设置qt.conf文件)
在网上直接下载别人编译好的Qt库,为自己使用省了不少事.但往往也会遇到些问题,其中Qt version is not properly installed,please run make instal ...
- 1.预处理,生成预编译文件(.文件): Gcc –E hello.c –o hello.i 2.编译,生成汇编代码(.s文件): Gcc –S hello.i –o hello.s 3.汇编,生成目标文件(.o文件): Gcc –c hello.s –o hello.o 4.链接,生成可执行文件: linux笔记
1 动态查看日志 tail -f filename tail -1000f filename 2 解压当前目录内容为xxx.zip zip -r xxx.zip ./* 3 查看内存使用情况 fre ...
- 使用vue-cli脚手架搭建项目,保存编译时出现的代码检查错误(ESLint)
一.问题 出现这么写错误是什么原因呢?相信很多小白都会像我一样,第一次接触时有点二丈和尚摸不着头脑.其实是在你用vue-cli脚手架构建项目时用了ESLint代码检查工具,如下图 那么什么是ESLin ...
- 【Andrioid】在Gradle编译时生成一个不同的版本号,动态设置应用程序标题,应用程序图标,更换常数
写项目的时候常常会遇到下面的情况: 1.须要生成測试版本号和正式版本号的apk 2.測试版本号和正式版本号的URL是不一样的 3.測试版本号和正式版本号的包名须要不一致,这样才干安装到同一部手机上面. ...
- React系列文章:Babel编译JSX生成代码
上次我们总结了React代码构建后的Webpack模块组织关系,今天来介绍一下Babel编译JSX生成目标代码的一些规则,并且模拟整个生成的过程. 我们还是拿最简单的代码举例: import {gre ...
- 预编译加速编译(precompiled_header),指定临时文件生成目录,使项目文件夹更干净(MOC_DIR,RCC_DIR, UI_DIR, OBJECTS_DIR),#pragma execution_character_set("UTF-8")"这个命令是在编译时产生作用的,而不是运行时
预编译加速编译 QT也可以像VS那样使用预编译头文件来加速编译器的编译速度.首先在.pro文件中加入: CONFIG += precompiled_header 然后定义需要预编译的头文件: PREC ...
- Metalama简介2.利用Aspect在编译时进行消除重复代码
上文介绍到Aspect是Metalama的核心概念,它本质上是一个编译时的AOP切片.下面我们就来系统说明一下Metalama中的Aspect. Metalama简介1. 不止是一个.NET跨平台的编 ...
- .net core编译时设置不自动生成“netcoreapp3.0”目录
不知道出于什么目的,.netcore项目默认编译时生成的文件要多加一层"netcoreapp3.0"或"netcoreapp2.1",这应该不符合大多数开发者的 ...
随机推荐
- 基于.NET MVC的高性能IOC插件化架构
基于.NET MVC的高性能IOC插件化架构 最近闲下来,整理了下最近写的代码,先写写架构,后面再分享几个我自己写的插件 最近经过反复对比,IOC框架选择了Autofac,原因很简单,性能出众,这篇博 ...
- 换行符以及for循环的优化
string str = ""; for (int i = 0; i < _errlistCusEmailInfo.Count; i++) ...
- 记录近期小改K-Means至MapReduce上的心得
背景: 在所有聚类算法中KMeans算是表面上最简单的一种,没有过多恼人的古希腊符号公式,没有过分繁杂的公式嵌套.对于一个初学矩阵或者仅有向量概念的非专业人士的来说,不可不畏是一把踹门利器.这个世界上 ...
- C++并发编程学习笔记<1> 入门
入门 多线程C++程序是什么样子的? 它看上去和其它全部C++程序一样,一般是变量.类以及函数的组合. 唯一真正的差别在于某些函数能够并发执行, 当然.为了并发地执行函数,必须使用特定的函数以及对象来 ...
- 给phpcms v9加入一个主题radio无线电button,它可反复使用,以创建不同的专题部分内容编辑器,添加一个主题来定义自己的领域
1. 2. 找到 phpcms\modules\special\templates中的special_add.tpl.php和special_edit.tpl.php文件 special_add.tp ...
- win7访问xp共享访问不了
这个问题不是一天两天了,经历几次了,所以记下来. 1. 一些XP对用户权限作了特殊的优化设置.限制了只有guest用户才能用于做局域网共享用户. 2. 大多数时候,需要设置一个密码,才能用于访问. 3 ...
- jQuery EasyUI API - Grid - DataGrid [原创汉化官方API]
最近在学习jQuery EasyUI,发现中文的文档好少,部分文档不错但它是鸟语的,为了大家也为了自己学习吧,汉化做一下笔记. 有没有说清楚的,或者翻译不正确的地方还请大家谅解指出.. 由于工作时间原 ...
- DDD分层架构之领域实体(基础篇)
DDD分层架构之领域实体(基础篇) 上一篇,我介绍了自己在DDD分层架构方面的一些感想,本文开始介绍领域层的实体,代码主要参考自<领域驱动设计C#2008实现>,另外参考了网上找到的一些示 ...
- HTTP 报文中的 Header 字段进行身份验证
[小技巧][ASP.Net MVC Hack] 使用 HTTP 报文中的 Header 字段进行身份验证 在一些 Web 系统中,身份验证是依靠硬件证书进行的:在电脑上插入 USB 证书,浏览器插件读 ...
- Solr安装(Tomcat)
Solr安装(Tomcat) 安装环境 Windows 7 64bit Apache-tomcat-8.0.9-windows-x64 Solr-4.9.0 JDK 1.8.0_05 64bit ...