一:特性是什么?特性怎么创建怎么使用?

这一章节,我想谈谈c#的特性方面的知识,特性大家在工作开发中都很熟悉,比如我们经常见到的

1:key Display --EF
2:Import
3:HttpGet HttpPost HttpDelete --MVC/WebApi
4:Serializable,Obsolete --系统单独功能
5:AutoMapFrom
6:WebMethod --WebService
7:Injection InjectionConstractor InjectMethod --IOC的特性 
这些特性我们运用时感觉很简单,只需要简简单单的在类或者属性或者方法上面加 [特性的名字] 有时候就能实现我们想要的效果,那今天我们就来揭开特性的面纱,看看特性到底是什么以及是怎么实现一些功能的?如想知道,请继续往下看!
 
 
通过使用反编译工具看IL中间语言发现,特性就是一个类,直接继承/间接继承Attribute父类,约定俗称使用Attribute结尾,标记的时候可以省略掉,可以使用[]包裹标记到元素,其实就调用的无参构造函数, 特性起到标记的作用,从而影响编译器[Obsolete] 或者影响程序的运行([Serializable])等,下面我们创建一个特性如下:
    /// <summary>
/// 是给枚举用 提供一个额外信息
/// AllowMultiple特性影响编译器,AttributeTargets修饰的对象 AllowMultiple:能否重复修饰 Inherited:是否可继承
/// 可以指定属性和字段
/// </summary>
[AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field,AllowMultiple =true,Inherited =true)]
public class RemarkAttribute : Attribute
{
public RemarkAttribute()
{
}
public RemarkAttribute(string remark)
{
this.Remark = remark;
}
public string Description; //字段
public string Remark { get; private set; }
}

然后特性类上面的AttributeUsage也是一个特性,具体的用处见上面的注释解释,特性创建好了,我们可以创建一个实体,然后再实体的字段上面使用这个特性,具体如下:

    [Remark("用户状态")]
public enum UserState
{
/// <summary>
/// 正常
/// </summary>
[Remark("正常")]
Normal = ,
/// <summary>
/// 冻结
/// </summary>
[Remark("冻结")]
Frozen = ,
/// <summary>
/// 删除
/// </summary>
[Remark("删除")]
Deleted =
}

因为AttributeTargets.Enum标识这个特性可以放在枚举上面,那我们上面那种代码也是完全被允许的,此外,AttributeTargets如果不写,则默认是全部都可以使用的!特性创建和特性标识已经准备好了,然而怎么使特性生效呢?这个还是需要我们写代码来实现的

 public static class RemarkExtend
{
/// <summary>
/// 扩展方法
/// </summary>
/// <param name="enumValue"></param>
/// <returns></returns>
public static string GetRemark(this Enum enumValue)
{
Type type = enumValue.GetType();
FieldInfo field = type.GetField(enumValue.ToString());
if (field.IsDefined(typeof(RemarkAttribute), true))
{
RemarkAttribute remarkAttribute = (RemarkAttribute)field.GetCustomAttribute(typeof(RemarkAttribute));
return remarkAttribute.Remark;
}
else
{
return enumValue.ToString();
}
}
}

使特性的生效的代码已经写好了,然后我们如果想要获得一个枚举的中文名字可以通过下面调用

 UserState userState = UserState.Normal;
Console.WriteLine(userState.GetRemark());

这样我们就可以随心所欲的获取到这个枚举的中文备注了,没有使用特性之前,我们想要获取到枚举的中文备注,一般会只能写死判断,如下:

 UserState userState = UserState.Normal;
if (userState == UserState.Normal)
{
Console.WriteLine("正常状态");
}
else if (userState == UserState.Frozen)
{
Console.WriteLine("冻结状态");
}
else
{
Console.WriteLine("删除状态");
}

然后一旦要修改状态名字,则代码也随着修改,这就会导致维护比较困难,如果使用了特性,则会用到的地方不需要太关注这些文字,只需要调用,然后修改的时候,只需要修改枚举上面的文字即可,极其容易维护!

二:特性的运用范围

特性运用范围极其广,框架中我们看到上面的总结就晓得了,下面的我总结了以下几个地方也可以使用特性

1:数据展示 不想展示属性名字,而是用中文描述
2:想指定哪个是主键,哪个是自增
3:别名 数据库里面叫A 程序是B,怎么映射等

然后特性还可以校验一些数据字段等,下面我写个例子,以便更加容易理解:

1:先创建数据校验的特性

 public abstract class AbstractValidateAttribute : Attribute
{
public abstract bool Validate(object oValue);
} public class LongValidateAttribute : AbstractValidateAttribute
{
private long _lMin = ;
private long _lMax = ;
public LongValidateAttribute(long lMin, long lMax)
{
this._lMin = lMin;
this._lMax = lMax;
} public override bool Validate(object oValue)
{
return this._lMin < (long)oValue && (long)oValue < this._lMax;
}
}
public class RequirdValidateAttribute : AbstractValidateAttribute
{
public override bool Validate(object oValue)
{
return oValue != null;
}
}

2:再一个实体类上面的字段增加特性

public class Student
{ [RequirdValidate]
public int Id { get; set; } [LongValidate(,)]//还有各种检查
public string Name { get; set; }
[LongValidate(, )]
public string Accont { get; set; } /// <summary>
/// 10001~999999999999
/// </summary>
[LongValidate(, )]
public long QQ { get; set; } }

3:写下面的方法,使特性生效

public class DataValidate
{
public static bool Validate<T>(T t)
{
Type type = t.GetType();
//IsDefined 是判断,不会调用构造函数
//if (type.IsDefined(typeof(AbstractValidateAttribute), true))
//{
// //调用构造函数
// var oAttributeArray = type.GetCustomAttributes(typeof(AbstractValidateAttribute), true);
// foreach (var item in oAttributeArray)
// { // }
//}
//foreach (var method in type.GetMethods())
//{
// if (method.IsDefined(typeof(AbstractValidateAttribute), true))
// {
// object item = method.GetCustomAttributes(typeof(AbstractValidateAttribute), true)[0];
// AbstractValidateAttribute attribute = item as AbstractValidateAttribute;
// //if (!attribute.Validate(method.GetValue(t)))
// //{
// // result = false;
// // break;
// //}
// }
//}
bool result = true;
foreach (var prop in type.GetProperties())
{
if (prop.IsDefined(typeof(AbstractValidateAttribute), true))
{
object item = prop.GetCustomAttributes(typeof(AbstractValidateAttribute), true)[];
AbstractValidateAttribute attribute = item as AbstractValidateAttribute;
if (!attribute.Validate(prop.GetValue(t)))
{
result = false;
break;
}
}
}
return result;
}
}

4:应用判断时如下:

Student student = new Student();
student.Id = ;
student.Name = "MrSorry";
student.QQ = ;
var result = DataValidate.Validate(student);

这样就完成了数据校验,特性校验的特点,总结得到了如下三点:

1:可以校验多个属性
2:可以支持多重校验
3:支持规则的随意扩展

运用了这个特性校验后,就不用再每个地方再分别写校验的逻辑,简单易用!

c#中的特性Attribute的更多相关文章

  1. C#中的特性 (Attribute) 入门 (二)

    C#中的特性 (Attribute) 入门 (二) 接下来我们要自己定义我们自己的特性,通过我们自己定义的特性来描述我们的代码. 自定义特性 所有的自定义特性都应该继承或者间接的继承自Attribut ...

  2. C#中的特性 (Attribute) 入门 (一)

    C#中的特性 (Attribute) 入门 (一) 饮水思源 http://www.cnblogs.com/Wind-Eagle/archive/2008/12/10/1351746.html htt ...

  3. c#核心基础 - 浅谈 c# 中的特性 Attribute)

    特性(Attribute)是用于在运行时传递程序中各种元素(比如类.方法.结构.枚举.组件等)的行为信息的声明性标签.可以通过使用特性向程序添加声明性信息.一个声明性标签是通过放置在它所应用的元素前面 ...

  4. .net中的特性

    本文来之:http://hi.baidu.com/sanlng/item/afa31eed0a383e0e570f1d3e 在一般的应用中,特性(Attribute,以称为属性)好像被使用的不是很多. ...

  5. [C#] 剖析 AssemblyInfo.cs - 了解常用的特性 Attribute

    剖析 AssemblyInfo.cs - 了解常用的特性 Attribute [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5944391.html 序 ...

  6. [C#] C# 知识回顾 - 特性 Attribute

    C# 知识回顾 - 特性 Attribute [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5911289.html 目录 特性简介 使用特性 特性 ...

  7. C# 知识特性 Attribute

    C#知识--获取特性 Attribute 特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集.类型.方法.属性等)相关联.特性与程序实体关联后,可在运行时使用"反射"查询 ...

  8. C#中的 特性 详解(转载)

    本篇幅转载于:http://www.cnblogs.com/rohelm/archive/2012/04/19/2456088.html C#中特性详解 特性提供了功能强大的方法,用于将元数据或声明信 ...

  9. 区分元素特性attribute和对象属性property

    × 目录 [1]定义 [2]共有 [3]例外[4]特殊[5]自定义[6]混淆[7]总结 前面的话 其实attribute和property两个单词,翻译出来都是属性,但是<javascript高 ...

随机推荐

  1. [swarthmore cs75] Compiler 6 – Fer-de-lance

    课程回顾 Swarthmore学院16年开的编译系统课,总共10次大作业.本随笔记录了相关的课堂笔记以及第8次大作业. First-class function: It treats function ...

  2. stm32f10x_it.c、stm32f10x_it.h和stm32f10x_conf.h文件作用

    如上图,在STM32的Keil工程文件(Project)中一般都包含stm32f10x_it.c.stm32f10x_it.h和stm32f10x_conf.h这三个文件,但是在ST官方提供的标准库“ ...

  3. STM32-跑马灯实验

    实验环境: STM32开发板 Keil uVision4 FlyMcu.exe 一. 建立文件夹 1.建立跟文件夹"BASE"(名称任意),再在其下建立四个子文件夹 2. 在&qu ...

  4. <笔记>原生PHP访问TP模板变量

    在模板中,原生PHP可以直接访问模板变量,不过如果模板变量是数组,要访问数组中元素时不能使用"."符号,只能通过数组['元素名']的方式

  5. java面试问题收集(2)

    1 Integer int相等问题 Integer对象和int比较的时候会有一个拆箱的过程,始终相等 Integer和new Integer对象不会相等,引用不同 两个Integer对象比较,Inte ...

  6. 急速安装lnmp 编译版本

    急速安装lnmp 编译版本 安装msyql+PHP 系统centos6.5 安装 开发软件包 已经改成了163的源需要执行下面的代码 官网不自带 libmcrypt libmcrypt-devel w ...

  7. Solidity: ParserError: Expected pragma, import directive or contract/interface/library definition.

    第一行忘记加分号 pragma solidity ^0.4.0;

  8. 解决expect自动登录,rz和sz不能使用问题

    一.问题描述: 解决expect自动登录,rz和sz不能使用问题: 二.解决方法: 1. 临时修改环境变量: 将本地的LC_CTYPE环境变量设置成en_US export LC_CTYPE=en_U ...

  9. spring 框架学习网站

    spring 框架学习网站 NO1 http://www.mkyong.com NO2 https://spring.io/docs/reference

  10. 关于git的reset指令说明-soft、mixed、hard

    在开发过程中,git的版本管理越来越普及.在版本管理中,最常用和最重要的是重置提交的版本,恢复后悔做了的事.大家都知道用reset命令.但是有几种形态需要整理共享一下,也方便我自己查阅. 一.首先解析 ...