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

这一章节,我想谈谈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. 查询树节点、oracle、select...start with...connect by prior...

    通过子节点向根节点追朔. select * from persons.dept start with deptid=76 connect by prior paredeptid=deptid 通过根节 ...

  2. C#使用Dotfuscator混淆代码的加密方法

    C#编写的代码如果不进行一定程度的混淆和加密,那么是非常容易被反编译进行破解的,特别是对于一些商业用途的C#软件来说,因为盯着的人多,更是极易被攻破.使用VS自带的Dotfuscator可以实现混淆代 ...

  3. display:inline-block; 在css中是什么意思?

    inline-block主要的用处是用来处理行内非替换元素的高宽问题的!行内非替换元素,比如span.a等标签,正常情况下士不能设置宽高的,加上该属性之后,就可以触发让这类标签表现得如块级元素一样,可 ...

  4. 安卓端 - H5页面在微信分享、收藏、保存图片不成功

    经过代码实践: 原因是微信在分享.收藏和保存时会获取到图片信息,当图片过大时,造成失败

  5. 6 week work 3

    sticky vs fixed sticky:表示粘贴到某个位置.当组件设置了该属性值后,当页面滑动时,组件会跟着页面移动,当组件触及到窗体后,页面若继续滑动,组件则处在与窗体接触的位置不动.元素的定 ...

  6. linux系统下安装redis以及java调用redis

    关系型数据库:MySQL  Oracle 非关系型数据库:Redis 去掉主外键等关系数据库的关系性特性 1)安装redis编译的c环境,yum install gcc-c++ 2)将redis-2. ...

  7. [转] Snapshotting with libvirt for qcow2 images

    http://kashyapc.com/2011/10/04/snapshotting-with-libvirt-for-qcow2-images/ Libvirt 0.9.6 was recentl ...

  8. C#.NET开源项目、机器学习、Power BI

    [总目录]本博客博文总目录-实时更新   阅读目录 1.开源Math.NET基础数学类库使用系列 2.C#操作Excel组件Spire.XLS文章目录 3.彩票数据资料库文章 4.数据挖掘与机器学习相 ...

  9. VS2013和NuGet

    1.前言 有时候在使用VS2013时需要用到第三方的dll,这时候NuGet就是一个很方便的工具.但是这个小东东也是和VS不同的版本相关的,最开始不知道,乱安装一气,最后就是很多情况下不能用.这两天在 ...

  10. 深度学习Tensorflow生产环境部署(下·模型部署篇)

    前一篇讲过环境的部署篇,这一次就讲讲从代码角度如何导出pb模型,如何进行服务调用. 1 hello world篇 部署完docker后,如果是cpu环境,可以直接拉取tensorflow/servin ...