【我们一起写框架】C#的AOP框架

原文:【我们一起写框架】C#的AOP框架

前言

AOP,大家都是听过的,它是一种面向切面的设计模式。

不过AOP虽然是被称为设计模式,但我们应该很少能看到AOP设计的框架。为什么呢?

因为,AOP单独设计的框架几乎是无法使用的。普遍的情况是,AOP要是和其他设计模式结合在一起使用。

所以,AOP虽然是设计模式,但我认为它更接近一种设计元素,是我们在设计框架的作料。

其实AOP的原理就是将公共的部分提取出来,这件事,即便不考虑设计模式,每个开发人员在工作时也是会做的。也就是说,在AOP设计模式被提出来之前,我们就在应用AOP的设计了。

那么,为什么还要单独将AOP拿出来说事呢?

我认为,主要目的应该是要强化切面的重要性。因为设计框架时加入AOP的理念,确实会让框架更加立体。

AOP的应用

AOP既然是一种作料,那么它的应用就是多种多样的;它可以出现在任何场合的。

下面我们举出一个例子,来说明AOP的应用。

----------------------------------------------------------------------------------------------------

我们在开发的时候,通常会有这样的需求。

[将函数的入参和返回值记录到日志中][入参中为负数抛出异常]

当我们面对这样的需求时,通常会将入参和返回值全部传到一个独立的操作函数中,对其进行相应的操作。

这样实现,就是AOP的理念;不过开发者处理时,稍微繁琐了一点,因为每个函数都要处理。

为了减少这种重复操作,让我们一起来编写函数的切面AOP吧。

AOP框架的实现

首先,我们一起看下AOP框架应用后的效果。

在下面代码中,可以看到,我们定义了一个AOPTest类,然后调用了他的Test方法,之后传入了一个正数和一个负数,如果函数抛出异常,我们将输出异常的消息。

class Program
{static void Main(string[] args){AOPTest test = new AOPTest();try{ test.Test(518);test.Test(-100);}catch(Exception ex){Console.WriteLine(ex.Message);}Console.ReadLine();}
}

接下来我们看下AOPTest类的定义。

[Kiba]
public class AOPTest : ContextBoundObject
{ public string Test(int para){Console.WriteLine(para);return "数字为:" + para;}
}

代码如上所示,很简单,就是输出了入参,不过有两个地方需要注意,该类继承了ContextBoundObject类,并且拥有一个KIba的特性。

然后,我们看下运行结果。

从运行结果中我们看到,第一个函数正常输出,但第二个函数抛出了异常,而且异常的Message是异常两个汉字。

这就是我们AOP实行的效果了,我们的AOP框架对函数入参进行了判断,如果是正数,就正常运行,如果为负数就抛出异常。

下面我们一起来看看AOP框架是如何实现这样的效果的。

首先我们一起来看下Kiba这个特性。

[AttributeUsage(AttributeTargets.Class)]
public class KibaAttribute : ContextAttribute
{public KibaAttribute(): base("Kiba"){} public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg){ctorMsg.ContextProperties.Add(new KibaContextProperty()); }
}

代码如上所示,很简单很基础的一个特性,不过它继承了ContextAttribute类,并重写了其下的方法GetPropertiesForNewContext。

这个方法是干什么的呢?

我们可以从函数名的直译来理解它是干什么的,GetPropertiesForNewContext直译过来就是创建新对象时获取他的属性。然后我们看到,我们重新了该方法后又为他添加了一个新的属性。

而我们添加的这个新的属性将截获拥有该特性的类的函数。

【PS:该描述并不是ContextAttribute真实的运行逻辑,不过,初学时,我们可以先这样理解,当我们更深入的理解了函数的运行机制后,自然就明白该类的意义。】

 下面我们看下KibaContextProperty类。

public class KibaContextProperty : IContextProperty, IContributeObjectSink
{public KibaContextProperty(){} public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink next){return new KibaMessageSink(next);} public bool IsNewContextOK(Context newCtx){return true;}  public void Freeze(Context newCtx){}  public string Name{get { return "Kiba"; }}
}

代码如上所示,依然很简单,只是继承并实现了IContextProperty和IContributeObjectSink两个接口。

其中我们重点看下GetObjectSink方法,该方法用于截获函数。

我们可以看到该方法的两个参数,但我们只用到了一个IMessageSink ,并且,该方法的返回值也是IMessageSink。

所以,我们可以想到,该方法的本来面目是这样的。

public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink next)
{return next; 
} 

也就是说,IMessageSink 封装了函数的一切内容,那么我们的AOP实现的地方也就找到了。

于是我们用KibaMessageSink类处理一下IMessageSink 。

KibaMessageSink代码如下:

public class KibaMessageSink : IMessageSink
{private KAspec kaspec = new KAspec(); private IMessageSink nextSink; public KibaMessageSink(IMessageSink next){nextSink = next;} public IMessageSink NextSink{get{return nextSink;}} public IMessage SyncProcessMessage(IMessage msg){ IMethodCallMessage call = msg as IMethodCallMessage; if (call != null){//拦截消息,做前处理kaspec.PreExcute(call.MethodName, call.InArgs);}for (int i = 0; i < call.InArgs.Count(); i++){var para = call.InArgs[i];var type = para.GetType();string typename = type.ToString().Replace("System.Nullable`1[", "").Replace("]", "").Replace("System.", "").ToLower();if (typename == "int32"){int inparame = Convert.ToInt16(call.InArgs[i]);if (inparame < 0){throw new Exception("异常");}} }//传递消息给下一个接收器 IMessage retMsg = nextSink.SyncProcessMessage(call as IMessage);   IMethodReturnMessage dispose = retMsg as IMethodReturnMessage;if (dispose != null){ //调用返回时进行拦截,并进行后处理kaspec.EndExcute(dispose.MethodName, dispose.OutArgs, dispose.ReturnValue, dispose.Exception);} return retMsg;} public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink){return null;} 
}

我们重点看下SyncProcessMessage方法。

可以看到,我们在方法调用先调用了KAspec类的PreExcute方法,该方法用于把入参输出到日志中。

接下来,我们对入参进行了判断,如果入参是负数,我们将不执行函数,直接抛出异常。

然后我们调用KAspec类的EndExcute方法,将返回值输出到日志中。

再然后,我们才返回IMessage,让函数完结。

下面我们一起看下KAspec类的实现。

/// <summary>
/// 切面
/// </summary>
public class KAspec
{ #region 处理/// <summary>/// 前处理/// </summary> public void PreExcute(string MethodName, object[] InParams){Logger.Info("==================== " + MethodName + ":" + " Start====================");Logger.Info(string.Format("参数数量:{0}", InParams.Count()));for (int i = 0; i < InParams.Count(); i++){Logger.Info(string.Format("参数序号[{0}] ============    参数类型:{1}    执行类:{1}", i + 1, InParams[i])); Logger.Info("传入参数:");string paramXMLstr = XMLSerializerToString(InParams[i], Encoding.UTF8);Logger.Info(paramXMLstr);}} /// <summary>/// 后处理/// </summary> public void EndExcute(string MethodName, object[] OutParams, object ReturnValue, Exception ex){Type myType = ReturnValue.GetType();Logger.Info(string.Format("返回值类型:{0}", myType.Name));Logger.Info("返回值:");if (myType.Name != "Void"){string resXMLstr = DataContractSerializerToString(ReturnValue, Encoding.UTF8);Logger.Info(resXMLstr);}if (OutParams.Count() > 0)//out 返回参数{Logger.Info(string.Format("out返回参数数量:{0}", OutParams.Count())); for (int i = 0; i < OutParams.Count(); i++){Logger.Info(string.Format("参数序号[{0}] == 参数值:{1}", i + 1, OutParams[i]));}}if (ex != null){Logger.Error(ex);}Logger.Info("==================== " + MethodName + ":" + " End====================");}
}

代码如上所示,就是简单的日志输出。

到此,我们的AOP框架就编写完成了;其上的代码编写都是为KAspec服务,因为KAspec才是切面。

也就是说,只要将特性Kiba赋予给类,那么该类的函数,就被拦截监听,然后我们就可以KAspec切面中,做我们想做的操作了。

最后,我们再回头看下AOPTest类。

[Kiba]
public class AOPTest : ContextBoundObject

可以看到,该类不止拥有Kiba特性,还继承了ContextBoundObject类,该类是干什么的呢?

ContextBoundObject类是内容边界对象,只有继承了ContextBoundObject类的类,其类中才会驻留的Context上下文,并且会被ContextAttribute特性拦截监听。

呃,其实,这样解释还是有点不太正确,不过我也没找到更好的说明方式,如果你还理解不了,也可以去MSDN查询下,当然,MSDN的解释是反人类的,需要做好心理准备。

----------------------------------------------------------------------------------------------------

框架代码已经传到Github上了,欢迎大家下载。

Github地址:https://github.com/kiba518/KAOP

----------------------------------------------------------------------------------------------------

注:此文章为原创,欢迎转载,请在文章页面明显位置给出此文链接!
若您觉得这篇文章还不错,请点击下右下角的推荐】,非常感谢!

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/281668.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新浪微博授权认证过程

为什么80%的码农都做不了架构师&#xff1f;>>> 一、授权认证 1、请求用户授权Token URL&#xff1a; https://api.weibo.com/oauth2/authorize HTTP请求方式:GET/POST 请求参数 必选 类型及范围 说明 client_id true string 申请应用时分配的AppKey。 redire…

VisualStudio 使用 FastTunnel 辅助搭建远程调试环境

有时候需要远程调试一些用户问题&#xff0c;期望能使用本机的 Visual Studio 开发环境&#xff0c;调试远程的用户的设备上的应用。这时会遇到的一个问题是如何让本机的 Visual Studio 可以连接上远程的用户的设备&#xff0c;从而进行调试。本文将告诉大家如何采用 FastTunne…

Python1

python介绍python是一种解释型的&#xff0c;面对对象的。带有动态语义的高级程序设计语言python简史1989年,Guido(龟叔)为ABC 语言写的一个插件。因Monty Python的喜剧团体的原因,故给这个语言起名为python。linux也是1989年诞生的,1991年正式发布linux1.0内核;1990年, 发布py…

ncut算法matlab实现,ncut_multiscale_1_6 经典的图像分割算法 的Matlab代码。 238万源代码下载- www.pudn.com...

文件名称: ncut_multiscale_1_6下载收藏√ [5 4 3 2 1 ]开发工具: matlab文件大小: 587 KB上传时间: 2015-04-17下载次数: 4提 供 者: HH详细说明&#xff1a;经典的图像分割算法NCut的Matlab代码。-Matlab code of classic image segmentation algorithm NCut .文件列表(…

使用.NET从零实现基于用户角色的访问权限控制

使用.NET从零实现基于用户角色的访问权限控制本文将介绍如何实现一个基于.NET RBAC 权限管理系统&#xff0c;如果您不想了解原理&#xff0c;可查看推送的另一篇文章关于Sang.AspNetCore.RoleBasedAuthorization[1] 库是使用介绍&#xff0c;直接使用该库即可。背景在设计系统…

数据归一化

数据归一化 数据的标准化是将数据按比例缩放&#xff0c;使之落入一个小的特定区间&#xff0c;一般为0到1之间。在某些比较和评价的指标处理中经常会用到&#xff0c;去除数据的单位限制&#xff0c;将其转化为无量纲的纯数值&#xff0c;便于不同单位或量级的指标能够进行比较…

.NET性能系列文章一:.NET7的性能改进

这些方法在.NET7 中变得更快照片来自 CHUTTERSNAP[1] 的 Unsplash[2]欢迎阅读.NET 性能系列的第一章。这一系列的特点是对.NET 世界中许多不同的主题进行研究、比较性能。正如标题所说的那样&#xff0c;本章节在于.NET7 中的性能改进。你将看到哪种方法是实现特定功能最快的方…

丁洪波 -- 不要“ 总是拿着微不足道的成就来骗自己”

都市快报实盘大赛25期&#xff1a;于海飞/丁洪波荣获冠亚军 七禾网 时间&#xff1a;2010-11-02 12:47:05 来源&#xff1a;期货中国10月30日下午&#xff0c;2010年浙商期货实盘大赛第三季度&#xff08;都市快报实盘大赛第25期&#xff09;颁奖典礼在天科大厦浙商期货大会议室…

面试专题(Mysql及Mongodb)

2019独角兽企业重金招聘Python工程师标准>>> mysql面试题 1. 各个数据库存储引擎区别 mysql的存储引擎是针对表进行设置的&#xff0c;一个库的不同表可以设置不同的存储引擎&#xff0c;mysql默认支持多种存储引擎&#xff0c;以适用不同领域的数据库应用需要&…

织梦网站翻页php,dedecms织梦网站列表页和内容页分页样式

织梦分页标签{dede:pagelist istitem"index,pre,next,end,option,info," listsize"5"/}&#xff0c;{dede:prenext getpre/}&#xff0c;{dede:prenext getnext/}。默认样式和使用模板css样式布局不一样,这时又不想重写样式&#xff0c;我们可以修改织梦标…

KDD走进阿里 数百专家聚集探讨产学研一体化

6月29日&#xff0c;由阿里巴巴集团、中国中文信息学会、KDD China联合主办的数据挖掘前沿发展与未来论坛在杭州举行&#xff0c;会议吸引了来自国际顶级高校和知名企业的近300名专家学者到场参会、近30000人在线观看。论坛除了分享最新的数据挖掘领域最新科研成果及研发思路外…

php模板引擎循环start,PHP模板引擎Smarty内建函数section,sectionelse用法详解

本文实例讲述了PHP模板引擎Smarty内建函数section,sectionelse用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;section 是 Smarty 模板中除了 foreach 以外的另一种处理循环的方案&#xff0c;section 比 foreach 要灵活&#xff0c;就像是一个改进的 foreach 语句…

OpenHarmony操作系统与龙芯2K1000LA芯片完成适配,龙架构平台获得开源鸿蒙认证

近日&#xff0c;龙芯中科与软通动力控股公司鸿湖万联共同完成OpenHarmony操作系统与龙芯2K1000LA处理器的适配&#xff0c;“乘风1000”开发板&#xff08;搭载龙芯2K1000LA&#xff09;荣获OpenHarmony生态产品兼容性证书。至此&#xff0c;万物互联的OpenHarmony生态体系再次…

struts2开发action 的三种方法以及通配符、路径匹配原则、常量

struts2开发action 的三种方法 1、继承ActionSupport public class UserAction extends ActionSupport {// Action中业务处理方法public String login() {System.out.println("UserAction.login()"); // return "success";return SUCCESS;} } 2、实现…

left join 和 inner join

2019独角兽企业重金招聘Python工程师标准>>> left join 和 inner join 首先 MySQL 中 inner join 的效率确实要高于 left join。所以没必要使用 left join 转弯成 inner join 的效果。这样不但效率降低&#xff0c;可读性也会降低。 Number1 select from t1 left j…

Vue3+.NET6,轻松开发管理后台!(可复用)

在GitHub是没找到简单好用的Vue3.NET6管理后台项目&#xff0c;有收藏的请评论区分享。这里分享一套Vue3 Axios TS Vite Element Plus .NET 6 WebAPI JWT SqlSugar的通用管理后台&#xff0c;前后端分离架构&#xff0c;各种最新框架组件&#xff0c;实现了管理后台几乎…

iOS网络请求安全认证(JWT,RSA)

在网络世界中&#xff0c;安全是一个很重要的问题&#xff0c;以往的HTTP请求已经不能承担这个安全任务&#xff0c;抓包工具一抓&#xff0c;你的所有网络请求全都曝光。当然&#xff0c;你可能会采用加密算法来加密数据&#xff0c;但是这仍然不够。 在移动端和服务器的通信过…

linux下mariadb大小写敏感

2019独角兽企业重金招聘Python工程师标准>>> Linux下安装好mariadb后&#xff0c;在使用时会发现mariadb对大小写敏感&#xff0c;这对开发带来一定的不利&#xff0c;这时只要在配置文件中配置一下&#xff0c;取消大小写敏感即可&#xff1a; sudo vi /etc/MySQL/…

评论列表显示及排序,个人中心显示

1.显示所有评论{% for foo in ques.comments %} 2.所有评论排序uquestion db.relationship(Question, backrefdb.backref(comments, order_bycreat_time.desc)) 3.显示评论条数{{ ques.comments|length }} 1题代码如下&#xff1a; <h3>评论区:({{ ques.comments|length…

他俩都曾是技术大牛,创业这些年来有怎样的苦与乐?

这是头哥侃码的第263篇原创国庆假期回来&#xff0c;「头哥唠 B 唠」的直播仍在继续。这次我邀请了我工作上的老板和朋友&#xff0c;一起聊了聊关于 “技术创业路上的苦与乐”。熟悉他们两位的都知道&#xff0c;可以说是技术出身&#xff0c;然后创业当老板的代表。大家都知道…