C#的特性Attribute

一、什么是特性

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

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

  特性不是修饰符而是一个有独特实例化形式的类,继承于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

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

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

相关文章

java 技能鉴定_JAVA试题-技能鉴定

一、单选题1.以下创建了几个对象( B)String A,B,CA"a";B"b":AAB;StringBuffer Dnew StringBuffer("abc");DD.append("567");A.6B.4C.3D.52.关于以下程序段&#xff0c;正确的说法是( C )1&#xff0e;String s1“a”“b”;2&#xff0…

ADD_SHORTCUT_ACTION

String ADD_SHORTCUT_ACTION 动作&#xff1a;在系统中添加一个快捷方式。. “android.intent.action.ADD_SHORTCUT”   String ALL_APPS_ACTION 动作&#xff1a;列举所有可用的应用。   输入&#xff1a;无。 “android.intent.action.ALL_APPS”   String ALTERNATIVE…

python3中朴素贝叶斯_贝叶斯统计:Python中从零开始的都会都市

python3中朴素贝叶斯你在这里 (You are here) If you’re reading this, odds are: (1) you’re interested in bayesian statistics but (2) you have no idea how Markov Chain Monte Carlo (MCMC) sampling methods work, and (3) you realize that all but the simplest, t…

java映射的概念_Java 反射 概念理解

文章来源:http://hollischuang.gitee.io/tobetopjavaer/#/basics/java-basic/reflection反射反射机制指的是程序在运行时能够获取自身的信息。在java中&#xff0c;只要给定类的名字&#xff0c;那么就可以通过反射机制来获得类的所有属性和方法。反射有什么作用在运行时判断任…

【转载】移动端布局概念总结

布局准备工作及布局思想及概念: 一个显示器&#xff08;pc端显示器 及 手机屏显示器&#xff09;&#xff0c;既有物理像素&#xff0c;又有独立像素&#xff08;独立像素也叫作css像素&#xff0c;用于前端人员使用&#xff09;&#xff1b; -->重要 首先确定设计稿的尺寸…

深入浅出:HTTP/2

上篇文章深入浅出&#xff1a;5G和HTTP里给自己挖了一根深坑&#xff0c;说是要写一篇关于HTTP/2的文章&#xff0c;今天来还账了。 本文分为以下几个部分&#xff1a; HTTP/2的背景HTTP/2的特点HTTP/2的协议分析HTTP/2的支持 HTTP/2简介 HTTP/2主要是为了解决现HTTP 1.1性能不…

画了个Android

画了个Android 今晚瞎折腾&#xff0c;闲着没事画了个机器人——android&#xff0c;浪费了一个晚上的时间。画这丫还真不容易&#xff0c;为那些坐标&#xff0c;差点砸了键盘&#xff0c;好在最后画出个有模有样的&#xff0c;心稍安。 下面来看看画这么个机器人需要些什么东…

数据治理 主数据 元数据_我们对数据治理的误解

数据治理 主数据 元数据Data governance is top of mind for many of my customers, particularly in light of GDPR, CCPA, COVID-19, and any number of other acronyms that speak to the increasing importance of data management when it comes to protecting user data.…

mysql 选择前4个_mysql从4个表中选择

不要认为GROUP BY是必需的 . 虽然如果一个孩子有2个父记录&#xff0c;你可能想用它来将2个父母分组到一行 - 但不确定这是否是你的要求 . 因为如果一个孩子有2个父母&#xff0c;那么将为该孩子返回的父母是未定义的 .假设所有孩子都有父母&#xff0c;所有父母都会有姓&#…

提高机器学习质量的想法_如何提高机器学习的数据质量?

提高机器学习质量的想法The ultimate goal of every data scientist or Machine Learning evangelist is to create a better model with higher predictive accuracy. However, in the pursuit of fine-tuning hyperparameters or improving modeling algorithms, data might …

mysql 集群实践_MySQL Cluster集群探索与实践

MySQL集群是一种在无共享架构(SNA&#xff0c;Share Nothing Architecture)系统里应用内存数据库集群的技术。这种无共享的架构可以使得系统使用低廉的硬件获取高的可扩展性。MySQL集群是一种分布式设计&#xff0c;目标是要达到没有任何单点故障点。因此&#xff0c;任何组成部…

Python基础:搭建开发环境(1)

1.Python语言简介 2.Python环境 Python环境产品存在多个。 2.1 CPython CPython是Python官方提供的。一般情况下提到的Python就是指CPython&#xff0c;CPython是基于C语言编写的。 CPython实现的解释器将源代码编译为字节码&#xff08;ByteCode&#xff09;&#xff0c;再由虚…

python数据结构之队列(一)

队列概念队列&#xff08;queue&#xff09;是只允许在一端进行插入操作&#xff0c;而在另一端进行删除操作的线性表。队列是一种先进先出的&#xff08;First In First Out&#xff09;的线性表&#xff0c;简称FIFO。允许插入的一端为队尾&#xff0c;允许删除的一端为队头。…

Android实现图片放大缩小

Android实现图片放大缩小 package com.min.Test_Gallery; import Android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.Matrix; import android.os.Bun…

matlab散点图折线图_什么是散点图以及何时使用

matlab散点图折线图When you were learning algebra back in high school, you might not have realized that one day you would need to create a scatter plot to demonstrate real-world results.当您在高中学习代数时&#xff0c;您可能没有意识到有一天需要创建一个散点图…

java判断题_【Java判断题】请大神们进来看下、这些判断题你都知道多少~

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼、判断改错题(每题2分&#xff0c;共20分)(正确的打√&#xff0c;错误的打并说明原因)1、 Java系统包提供了很多预定义类,我们可以直接引用它们而不必从头开始编写程序。 ( )2、 程序可以用字符‘*’替代一个TextField中的每个字…

PoPo数据可视化第8期

PoPo数据可视化 聚焦于Web数据可视化与可视化交互领域&#xff0c;发现可视化领域有意思的内容。不想错过可视化领域的精彩内容, 就快快关注我们吧 :) 微信订阅号&#xff1a;popodv_com谷歌决定关闭云可视化服务 Fusion Tables谷歌宣布即将关闭其 Fusion Tables 云服务&#x…

AC自动机题单

AC自动机题目 真的超级感谢xzy 真的帮到我很多 题单 [X] [luogu3808]【模板】AC自动机&#xff08;简单版&#xff09; https://www.luogu.org/problemnew/show/P3808[X] [luogu3796]【模板】AC自动机&#xff08;加强版&#xff09;https://www.luogu.org/problemnew/show/P37…

java list用法_Java List 用法详解及实例分析

Java List 用法详解及实例分析Java中可变数组的原理就是不断的创建新的数组&#xff0c;将原数组加到新的数组中,下文对Java List用法做了详解。List:元素是有序的(怎么存的就怎么取出来&#xff0c;顺序不会乱)&#xff0c;元素可以重复(角标1上有个3&#xff0c;角标2上也可以…

python字符串和List:索引值以 0 为开始值,-1 为从末尾的开始位置;值和位置的区别哦...

String&#xff08;字符串&#xff09;Python中的字符串用单引号 或双引号 " 括起来&#xff0c;同时使用反斜杠 \ 转义特殊字符。 字符串的截取的语法格式如下&#xff1a; 变量[头下标:尾下标]索引值以 0 为开始值&#xff0c;-1 为从末尾的开始位置。[一个是值&#x…