一、什么是特性

  特性是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签,这个标签可以有多个。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号([ ])来描述的。

  特性可以描述我们的代码,或者影响应用程序的行为。特性可以用来处理多种问题,比如序列化、数据验证、程序的安全特征等等。

  特性不是修饰符而是一个有独特实例化形式的类,继承于Attributes基类。其实我们在很多地方都能接触到特性,特性在平时的运用中是非常常见的,比如以下三个场景:

  1.特性[Serializable]标记可序列化的类

  [Serializable]public class MyObject { }

  2.特性[ServiceContract]指名WCF中可以用来对外调用的接口

  [ServiceContract]public interface IService{}

  3.特性[Range]用于MVC中类的属性的范围

  [Range(18, 60)]public int Age { get; set; }//年龄范围

二、预定义特性

  .Net框架已经给我们提供了一些预定义的特性,像是上面的三个场景的三个特性我们就可以直接拿来用。这里我们主要介绍另外三个比较基础的特性,它们都继承Attribute类,分别是:Obsolete、Conditional和AttributeUsage。

  1.Obsolete

  这个预定义特性标记了不应被使用的程序实体。它可以让您通知编译器丢弃某个特定的目标元素。例如,当一个新方法被用在一个类中,但是您仍然想要保持类中的旧方法,您可以通过显示一个应该使用新方法,而不是旧方法的消息,来把它标记为 obsolete(过时的)。

  • 参数 message,是一个字符串,描述项目为什么过时的原因以及该替代使用什么。
  • 参数 iserror,是一个布尔值。如果该值为 true,编译器应把该项目的使用当作一个错误。默认值是 false(编译器生成一个警告)。

  示例如下:

    [Obsolete("该方法已经过时,用NewMethod代替", true)]public static void OldMethod(){Console.WriteLine("OldMethod");}

  2.Conditional

  Conditional标记了一个条件方法,当满足谋个条件的时候该方法才能执行,多用于程序的调试和诊断。

  示例如下:

    #define Error //宏定义,决定那个方法执行using System;using System.Collections.Generic;using System.Diagnostics;using System.Text;namespace Attribute.Demo{class Program{static void Main(string[] args){Debug();Error();Console.ReadKey();}[Conditional("Debug")]public static void Debug(){Console.WriteLine("Debug");}[Conditional("Error")]public static void Error(){Console.WriteLine("Error");}}}    

  最后结果是:

    Error

  3.AttributeUsage

  预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它规定了自定义特性可应用到的项目的类型。这说明了该特性可以描述别的特性,对描述的特性进行某些规定。

  • 参数 validon 规定特性可被放置的语言元素。它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。
  • 参数 allowmultiple(可选的)为该特性的 AllowMultiple 属性(property)提供一个布尔值。如果为 true,则该特性是多用的。默认值是 false(单用的)。
  • 参数 inherited(可选的)为该特性的 Inherited 属性(property)提供一个布尔值。如果为 true,则该特性可被派生类继承。默认值是 false(不被继承)。

  示例如下:

    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)]

  可以规定多个可放置的语言元素,用标识符 | 分隔开来就行,上述代码就表示描述的特性可以用于属性和字段,如果标注在别的如类上就会报错。

三、自定义特性

  前面有提到预定义的特性都有继承自定义特性的基类Attribute,那么我们自己实现一个自定义特性也就需要继承Attribute类。那突然想到既然特性是一个类,那么为什么直接在描述目标前用方括号声明特性就可以又和一般的类有什么区别呢?主要有以下的一些区别和注意点:

  • 特性的实例化不是通过new的,而是在方括号中调用构造函数。并且构造函数可以有多个,构造函数里的参数为定位参数,定位参数必须放在括号的最前面,按照传入的定位参数可以调用相应的构造函数来实例化,如果有自己定义的构造函数则必须传入定位参数进行实例化否则报错。
  • 特性中属性的赋值,可以通过具名参数赋值,但是具名参数必须在定位参数后面,顺序可以打乱的,具体的形式如ErrorMessage = "年龄不在规定范围内"。

  接下来我就来自己实现验证属性值是否在规定区间内的特性,类似于[Range]。我们定义一个特性MyRangeAttribute继承基类Attribute,用预定义特性AttributeUsage规定只能用于描述属性,并自定义构造函数传入最小值和最大值,并定义方法Validate()校验,具体如下:

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]class MyRangeAttribute : System.Attribute{public MyRangeAttribute(int _min, int _max){this.max = _max;this.min = _min;}private int max;public int Max{get; set;}private int min;public int Min{get; set;}private string errorMessage;public string ErrorMessage{get; set;}public bool Validate(int _value){return _value >= min && _value <= max;}}

  接下来,我们创建一个Student类里面有Age属性并用我们的自定义特性MyRangeAttribute描述,Student类继承People类,在People类中有方法IsValidate()通过反射执行特性的校验方法Validate(),具体如下:

    class Student: BaseClass{private int age;[MyRange(0,10, ErrorMessage = "年龄不在规定范围内")]public int Age{get;set;}}class BaseClass{public bool IsValidate(out string msg){msg = string.Empty;Type type = this.GetType();foreach (var prop in type.GetProperties()){foreach (var attribute in prop.GetCustomAttributes()){object[] parameters = new object[] { (int)prop.GetValue(this, null) };if ((bool)attribute.GetType().GetMethod("Validate").Invoke(attribute, parameters))return true;else{msg = attribute.GetType().GetProperty("ErrorMessage").GetValue(attribute,null).ToString();return false;}}}return false;}}

  我们在控制台程序中执行如下代码:

    static void Main(string[] args){string msg = string.Empty;Student student = new Student();while (true){Console.WriteLine("请输入年龄(输入exit退出):");string str = Console.ReadLine();if (str.Equals("exit"))break;else{student.Age = Convert.ToInt32(str);if (student.IsValidate(out msg))Console.WriteLine("验证通过");elseConsole.WriteLine(msg);}}}

  运行可以看到结果如下:

四、结尾

  通过上述的例子可以看出特性可以和反射配合来进行相应的操作,不过反射会消耗性能,并且特性类可以用别的特性描述。

  如果有什么问题可以留言讨论!谢谢阅读。

转载于:https://www.cnblogs.com/xwc1996/p/10145421.html

C#的特性Attribute相关推荐

  1. .net 特性 Attribute

    public sealed class RemarkAttribute : Attribute{public string Remark { get; set; }// 构造函数public Rema ...

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

    定义 元素特性attribute是指HTML元素标签的特性 下面的id.class.title.a都是特性,其中a叫做自定义特性 <div id="id1" class=&q ...

  3. .NET基础编程之特性 - Attribute

    这一篇文章是给大家介绍的是:.NET基础编程之特性 - Attribute,对这一部分掌握不熟悉的同学,可以仔细的看一下! 一.特性简介 特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集. ...

  4. Unity游戏开发——C#特性Attribute与自动化

    这篇文章主要讲一下C#里面Attribute的使用方法及其可能的应用场景. 比如你把玩家的血量.攻击.防御等属性写到枚举里面.然后界面可能有很多地方要根据这个枚举获取属性的描述文本. 比如你做网络框架 ...

  5. 特性Attribute

    1.Attribute介绍    我们用VS进行编程时,智能提示再提供方法和属性列表的时候,有时会有下面的这种情况: 提示某个方法已经是过时的了,还会给与提示信息.出现此效果就是Attribute(特 ...

  6. C# 特性 Attribute

    特性就是在类的类名称.属性.方法等上面加一个标记,使这些类.属性.方法等具有某些统一的特征,从而达到某些特殊的需要.举个小栗子:方法的异常捕捉,你是否还在某些可能出现异常的地方(例如数据库的操作.文件 ...

  7. ABP的一些特性 (Attribute)

    大家应该很熟悉Attribute这个东西吧,ABP里面扩展了一些特性,做过滤权限,返回内容等进行控制,在这里小记下,方便后续查看. [DontWrapResult]  //ABP默认对返回结果做了封装 ...

  8. C#的特性(Attribute)详解

    C#特性是指我们可以对类.以及C#程序集中的成员进行进一步的描述,比如我们写一个关于人的类Person,该类可以对人的属性以及某些行为(方法)进行描述.那么如果我们要对人类进行进一步描述呢,比如人这个 ...

  9. 基于特性(Attribute)的实体属性验证方案设计

      各位朋友,我是Payne,大家好,欢迎大家关注我的博客,我的博客地址是https://qinyuanpei.github.io.在这篇文章中,我想和大家探讨下数据校验的相关问题,为什么我会对这个问 ...

最新文章

  1. luogu P4847 银河英雄传说V2(FHQ - 平衡树)
  2. Android之选项菜单创建
  3. QTP中使用ExecuteFile加载vbs脚本
  4. PHP导入Excel和导出Excel
  5. 【并查集】【图论】【最小生成树】剑鱼行动(ssl 1618)
  6. python自动化常用数字_Python全栈自动化系列之Python编程基础(基本数据类型)
  7. Web---session技术代码演示(request,session,servletContext)
  8. 将DataGrid中的数据导出为Excel的方法
  9. Dilated Convolutions 空洞卷积
  10. 基于51单片机的多点8路温度采集系统 proteus仿真程序原理图设计
  11. goolgle支付配置备忘录
  12. CSS —— 选择器
  13. 基于Python PIL库的简易马赛克拼图程序
  14. 浏览器主页被劫持篡改为hao123或者别的网页解决方法
  15. CSS3-设置基本边框和背景
  16. oracle stdevp函数,ORACLE和SQL语法区别归纳整理.doc
  17. 什么是http接口?
  18. 什么是「区块高度」?
  19. 超好看的粒子效果文字动画特效HTML5源码
  20. 技术男眼中的“TD式创新”:陈年旧账应该这么算

热门文章

  1. 如何从JavaScript数组中获取多个随机唯一元素?
  2. python获取当前日期_Python程序获取当前日期
  3. Java Double类doubleToLongBits()方法与示例
  4. C#| 使用String.Format()方法将小数点后的数字四舍五入
  5. 19-Harris角点检测
  6. 远控免杀专题2---msfvenom的隐藏参数
  7. java中的局部变量、成员变量、类变量
  8. makefile通用版本
  9. Redis高频面试笔记:java版本号比较算法
  10. configure: error: You need a C++ compiler for C++ support.