Attribute(特性)与AOP
提到特性,好多人都会疑惑特性(attribute),和注释有什么区别,简单来说,特性是给机器看的,而注释是给人看的。
特性不仅可以影响编译还可以影响运行,而注释只是为了让人更加容易理解、看懂代码而特别加注的解释而已。
那么怎么声明一个特性呢。
特性是一个继承或者间接继承Attribute的类
通常用attribute结尾,那么在使用的时候,可以去掉这个结尾
public class TableAttribute : Attribute
{
private string _TableName = null; public TableAttribute(string tableName)
{
this._TableName = tableName;
} public string GetTableName()
{
return this._TableName;
}
}
我们还可以通过特性来约束特性,只需要在声明特性的代码上加约束代码
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
AttributeTargers:约束特性使用范围;
AllowMultiple:是否允许多行
Inherited:是否允许继承
声明了特性后只需要在代码上加一行 [Table("User")]
[Table("User")]
public class UserModel
{
public int Id { get; set; }
/// <summary>
/// 账户
/// </summary>
public string Account
{
set;
get;
}
/// <summary>
/// 密码
/// </summary>
public string Password
{
set;
get;
}
/// <summary>
/// EMaill
/// </summary>
public string Email
{
set;
get;
}
/// <summary>
/// 手机
/// </summary>
public string Mobile
{
set;
get;
}
}
后面需要做的就是获取到这个table名称。
public static class Extend
{
public static string GetTable<T>(this T t) where T : new()
{
Type type = t.GetType();
object[] oAttribute = type.GetCustomAttributes(true);
foreach (var item in oAttribute)
{
if (item is TableAttribute)
{
TableAttribute attribute = item as TableAttribute;
return attribute.GetTableName();
}
}
return type.Name;
} }
最后调用。
class Program
{
static void Main(string[] args)
{
string name = user.GetTableName<UserModel>()
}
}
特性除了可以添加一些额外信息外,还可以验证信息,
比如验证数据是否在一定的数值范围。
首先声明一个特性
[AttributeUsage(AttributeTargets.Property)]
public class IntValidateAttribute : Attribute
{ private int _Min = 0;
private int _Max = 0; public IntValidateAttribute(int min, int max)
{
this._Min = min;
this._Max = max;
} public bool Validate(int num)
{
return num > this._Min && num < this._Max;
} }
然后在ID属性上加特性
[IntValidateAttribute(0, 10000)]
public int Id { get; set; }
这样就可以通过代码处理,达到验证并保存的目的。
public static void Save<T>(T t)
{
bool isSafe = true; Type type = t.GetType(); foreach (var property in type.GetProperties())
{
object[] oAttributeList = property.GetCustomAttributes(true);
foreach (var item in oAttributeList)
{
if (item is IntValidateAttribute)
{
IntValidateAttribute attribute = item as IntValidateAttribute;
isSafe = attribute.Validate((int)property.GetValue(t));
}
}
if (!isSafe)
break;
} if (isSafe)
Console.WriteLine("保存到数据库");
else
Console.WriteLine("数据不合法");
}
UserModel user = new UserModel();
BaseDAL.Save<UserModel>(user);
特性就是在不改变类的情况下额外的增加信息。
这也是AOP编程的主要思想。
软件设计因为引入面向对象思想而逐渐变得丰富起来。“一切皆为对象”的精义,使得程序世界所要处理的逻辑简化,开发者可以用一组对象以及这些对象之间的关系将软件系统形象地表示出来。而从对象的定义,进而到模块,到组件的定义,利用面向对象思想的封装、继承、多态的思想,使得软件系统开发可以向搭建房屋那样,循序渐进,从砖石到楼层,进而到整幢大厦的建成。应用面向对象思想,在设计规模更大、逻辑更复杂的系统时,开发周期反而能变的更短。自然其中,需要应用到软件工程的开发定义、流程的过程控制,乃至于质量的缺陷管理。但从技术的细节来看,面向对象设计技术居功至伟。然而,面向对象设计的唯一问题是,它本质是静态的,封闭的,任何需求的细微变化都可能对开发进度造成重大影响。
在面向对象中,类的本质还是静态的,在我们声明了一个类后,在以后的修改维护中,随着需求的增加,其实我们还是不愿意去动已经写好的类。
比如说我们有个用户注册类
public interface IUserProcessor
{
void RegUser(User user);
}
public class UserProcessor : IUserProcessor
{
public void RegUser(User user)
{
Console.WriteLine("用户已注册。Name:{0},PassWord:{1}", user.Name, user.Password);
}
}
但是后来我们希望在注册前和注册后都要来做一些事。这个时候 又不希望去动这个类,
在这里介绍一种设计模式,装饰器模式。用装饰器的模式去提供一个AOP功能
public class UserProcessorDecorator : IUserProcessor
{
private IUserProcessor UserProcessor { get; set; }//声明一个接口类型变量
public UserProcessorDecorator(IUserProcessor userprocessor)
{
UserProcessor = userprocessor;//创建对象时,直接把对象赋值给变量
} public void RegUser(User user)
{
PreProceed(user);
try
{
this.UserProcessor.RegUser(user);
}
catch (Exception)
{ throw;
}
PostProceed(user);
} public void PreProceed(User user)
{
Console.WriteLine("方法执行前");
} public void PostProceed(User user)
{
Console.WriteLine("方法执行后");
}
}
装饰器模式实现静态代理
AOP 在方法前后增加自定义的方法
public static void Show()
{
User user = new User() { Name = "XiMa", Password = "1234567890" };
IUserProcessor processor = new UserProcessor();
processor = new UserProcessorDecorator(processor);//UserProcessor直接赋值给构造函数
processor.RegUser(user);
}
最后怎么通过Unity 实现动态代理
首先,通过NuGet加载Unity

在类文件中引用
using Microsoft.Practices.Unity.InterceptionExtension;//InterceptionExtension扩展
using Microsoft.Practices.Unity;
public class UnityAOP
{
public static void Show()
{
User user = new User()
{
Name = "XiMa",
Password = "123123123123"
}; IUnityContainer container = new UnityContainer();//声明一个容器
container.RegisterType<IUserProcessor, UserProcessor>();//声明UnityContainer并注册IUserProcessor container.AddNewExtension<Interception>().Configure<Interception>()
.SetInterceptorFor<IUserProcessor>(new InterfaceInterceptor()); IUserProcessor userprocessor = container.Resolve<IUserProcessor>(); Console.WriteLine("********************");
userprocessor.RegUser(user);//调用
//userprocessor.GetUser(user);//调用
} #region 特性对应的行为
public class UserHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
User user = input.Inputs[0] as User;
if (user.Password.Length < 10)
{
return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位"));
}
Console.WriteLine("参数检测无误"); IMethodReturn methodReturn = getNext.Invoke().Invoke(input, getNext); //Console.WriteLine("已完成操作"); return methodReturn;
}
} public class LogHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
User user = input.Inputs[0] as User;
string message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
Console.WriteLine("日志已记录,Message:{0},Ctime:{1}", message, DateTime.Now);
return getNext()(input, getNext);
}
} public class ExceptionHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
IMethodReturn methodReturn = getNext()(input, getNext);
if (methodReturn.Exception == null)
{
Console.WriteLine("无异常");
}
else
{
Console.WriteLine("异常:{0}", methodReturn.Exception.Message);
}
return methodReturn;
}
} public class AfterLogHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
IMethodReturn methodReturn = getNext()(input, getNext);
User user = input.Inputs[0] as User;
string message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
Console.WriteLine("完成日志,Message:{0},Ctime:{1},计算结果{2}", message, DateTime.Now, methodReturn.ReturnValue);
return methodReturn;
}
} public class BeforeLogHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) {
IMethodReturn methodReturn = getNext()(input,getNext);
User user = input.Inputs[0] as User;
string message = string.Format("RegUser:Username:{0},Password:{1}", user.Name, user.Password);
Console.WriteLine("完成日志,Message:{0},Ctime:{1},计算结果{2}", message, DateTime.Now, methodReturn.ReturnValue);
return methodReturn;
}
} #endregion 特性对应的行为 #region 特性
public class UserHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
ICallHandler handler = new UserHandler() { Order = this.Order };
return handler;
}
} public class LogHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new LogHandler() { Order = this.Order };
}
} public class ExceptionHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new ExceptionHandler() { Order = this.Order };
}
} public class AfterLogHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new AfterLogHandler() { Order = this.Order };
}
} public class BeforeLofHandlerAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new BeforeLogHandler() { Order=this.Order};
}
}
#endregion 特性 #region 业务
[UserHandlerAttribute(Order = 1)]
[ExceptionHandlerAttribute(Order = 3)]
[LogHandlerAttribute(Order = 2)]
[AfterLogHandlerAttribute(Order = 5)]
public interface IUserProcessor
{
void RegUser(User user); } public class UserProcessor : IUserProcessor//MarshalByRefObject,
{
public void RegUser(User user)
{
Console.WriteLine("用户已注册。"); }
}
#endregion 业务 /*
TransparentProxyInterceptor:直接在类的方法上进行标记,但是这个类必须继承MarshalByRefObject...不建议用
VirtualMethod:直接在类的方法上进行标记,但这个方法必须是虚方法(就是方法要带virtual关键字)
InterfaceInterceptor:在接口的方法上进行标记,这样继承这个接口的类里实现这个接口方法的方法就能被拦截
*/
}
因为Unity好多都是固定写法,没有什么原理,直接给文件,大家可以自己去调试,尝试一下。
Attribute(特性)与AOP的更多相关文章
- 如何在方法上贴上attribute(特性)捕捉方法的异常,来实现我们的需求
在方法上贴上attribute(特性)捕捉方法的异常,其实这么做也是为了在项目中不会大量使用try-cacth这样的语句,同时使我们的代码看起来更简洁,更直观,将逻辑业务分离使得后期维护方便.这里我们 ...
- 【C#特性】 Attribute 特性
msdn:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/attributes/creating-c ...
- .net学习之Attribute特性和EF关键知识点
一.Attribute特性/标签1.Attribute用来对类.属性.方法等标注额外的信息,贴一个标签简单的说,定制特性Attribute,本质上就是一个类,它为目标元素提供关联附加信息,并在运行时以 ...
- [C#]Attribute特性(3)——AttributeUsage特性和特性标识符
相关文章 [C#]Attribute特性 [C#]Attribute特性(2)——方法的特性及特性参数 AttributeUsage特性 除了可以定制自己的特性来注释常用的C#类型外,您可以用At ...
- [C#]Attribute特性(2)——方法的特性及特性参数
上篇博文[C#]Attribute特性介绍了特性的定义,类的特性,字段的特性,这篇博文将介绍方法的特性及特性参数相关概念. 3.方法的特性 之所以将这部分单列出来进行讨论,是因为对方法的特性查询的反射 ...
- 关于C# 中的Attribute 特性
关于C# 中的Attribute 特性 作者: 钢钢 来源: 博客园 发布时间: 2011-01-09 23:30 阅读: 13921 次 推荐: 12 原文链接 [收藏] 摘要:纠结地说 ...
- Attribute特性验证模型model
数据验证我们往往分为前台验证和后台验证,而我们的后台验证每到一个方法中就要去验证一次,这样的代码想想都难以维护,这篇我们这篇文章就是为了解决这样的问题.用attribute 这个特性来解决这样的问题 ...
- .NET进阶篇03-Reflection反射、Attribute特性
知识需要不断积累.总结和沉淀,思考和写作是成长的催化剂 内容目录 一.概述二.反射1.反射使用2.创建对象3.调用方法4.字段属性三.特性四.总结 一.概述 反射其实无处不在,我们用VS进行调试时候, ...
- Net中Attribute特性的高级使用及自定义验证实现
好久没写博客了,今天在百忙之中抽空来写篇文章,记录一下最近深入学习Attribute特性的笔记及心得.~~ 一.什么是特性? 特性(Attribute)是用于在运行时传递程序中各种元素(比如类.方法. ...
- C#基础系列——Attribute特性使用
前言:上篇 C#基础系列——反射笔记 总结了下反射得基础用法,这章我们来看看C#的另一个基础技术——特性. 1.什么是特性:就博主的理解,特性就是在类的类名称.属性.方法等上面加一个标记,使这些类.属 ...
随机推荐
- 在Linux上创建Postgresql数据库
由于前一次用默认的配置创建pgsql数据库倒置root的占用率达到97%. 重新创建一次数据库,很多坑又忘了. 创建一个放Data的文件夹,/majestic12/pgsql/data PGDATA ...
- ASP.NET Core MVC 过滤器介绍
过滤器的作用是在 Action 方法执行前或执行后做一些加工处理.使用过滤器可以避免Action方法的重复代码,例如,您可以使用异常过滤器合并异常处理的代码. 过滤器如何工作? 过滤器在 MVC Ac ...
- CJOJ 1010【NOIP2003】加分二叉树 / Luogu 1040 加分二叉树(树型动态规划)
CJOJ 1010[NOIP2003]加分二叉树 / Luogu 1040 加分二叉树(树型动态规划) Description 设 一个 n 个节点的二叉树 tree 的中序遍历为( 1,2,3,-, ...
- 或许你不知道的10条SQL技巧(转自58沈剑原创)
这几天在写索引,想到一些有意思的TIPS,希望大家有收获. 一.一些常见的SQL实践 (1)负向条件查询不能使用索引 select * from order where status!=0 and s ...
- Android 应用退到后台
Android 应用退到后台 2016-4-21 10:29:26 Android L moveTaskToBack(boolean nonRoot) 把包含这个Activity的任务转到后台.并不是 ...
- JSON的详细介绍
JSON的语法可以表示以下三种类型的值: 简单值:可以表示字符串,数值,布尔值,null,但不支持undefined. 对象(Object):对象作为一种复杂数据类型,表示的是一组无序的键值对儿. 数 ...
- (转)eclipse报错及解决说明 "XX cannot be resolved to a type "
场景:在项目开发时,一个工程引用另一个工程中的文件,出现报错“XX cannot be resolved to a type”,但是在实际通过跟踪“F3”能够找到相应的文件,最终用方法4解决. 引言: ...
- (转)JAVA堆栈操作
java.util.Queue用法(是util中的一个接口) 队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作.进行插入操作的端称为队尾,进行 ...
- Js中有关变量声明和函数声明提升的问题
在ECMAScript5中没有块级作用域一说,只有函数作用域和全局作用域,在其中声明的变量和函数和其他语言的展现形式不同,在某些情况下不一定需要先定义后使用,函数和变量的使用可以在其声明之前,这到底是 ...
- 浅谈layer.open的弹出层中的富文本编辑器为何不起作用!
很多童鞋都喜欢用贤心的layui框架.是的,我也喜欢用,方便,简单.但是呢,有时候项目中的需求会不一样,导致我们用的时候,显示效果可能会不一样,好吧.这样的话,个别遇到的问题总是解决不好,但是呢还是那 ...