第十一节:特性(常见的特性标签、自定义特性、特性的使用案例)

一. 基本概念

1. 什么是特性?

 MSDN官方给出的定义时:公共语言运行时允许添加类似关键字的描述声明,叫做特性,它对程序中的元素进行标注,如类型、字段、方法和属性等。Attribute和Microsoft .Net Framework文件的元数据(metadata)保存在一起,可以用来向运行时描述你的代码,或者在程序运行时影响程序的行为。 

    我的理解:在不影响类封装的情况的下,额外的添加一些信息,如果你用这个信息,则特性有效;如果你不用这个信息,那么这个特性无效。我们通常使用反射的方式获取类、属性、或方法等上面标注的特性。

2. 分清三个概念

   (1). 注释:写在代码上面,一般用“ // ”和“ /**/ ”两个符号来表示,用来说明代码段或代码块的含义,方便自己或别人理解,对代码运行没有任何影响。

   (2). 属性:属性和特性虽然一字之差,但是完全两个不同的概念,属性在面向对象中,提供了私有或字段的封装,可以通过get和set访问器来设置可读可写。

   (3). 特性:不影响类的封装,在运行时,可以通过反射获取特性的内容。

3. DotNet中常用特性

   (1). [Serializable]和[NonSerialized] :表示可以序列化或不可以序列化。

   (2). [Obsolete("该类不能用了",true)]:表示该类(或属性或字段)将不能被使用。

   (3). [AttributeUsage]:用来限制特性的作用范围、是否允许多次修饰同一个对象、是否允许被继承。

   (4). [ReadOnly(true)]: 表示该特性作用于的属性为只读属性。

   (5). [Description("XXX")]:用来描述作用对象含义的。

   (6). [Flags]: 指示可以将枚举作为位域(即一组标志)处理

   (7). [DllImport("")]   : 使用包含要导入的方法的 DLL 的名称初始化

二. 自定义特性

1. 可作用的范围?

   程序集(assembly)、模块(module)、类型(type)、属性(property)、事件(event)、字段(field)、方法(method)、参数(param)、返回值(return)。

2. 约定规则?

  (1). 声明以Attribute结尾的类,即xxx+Attribute。

  (2). 必须继承或间接继承Attribute类。

  (3). 必须要有公有的构造函数。

3. 特性的使用方式(eg: ypfAttribute特性  mrAttribute特性)

  (1). 可以省略后缀,也可以不省略。  eg:[ypfAttribute]、[ypf]、[ypfAttribute()]、[ypf()]  。

  (2). 多个特性共同作用于一个对象的使用方式: [ypfAttribute][mrAttribute]、 [ypfAttribute,mrAttribute]  (注:也可以省略后缀的各种组合形式)

4. 特性的构建

  (1). 特性中除了可以声明构造函数,还可以声明属性和字段。(方法是不可以的)

  (2). 可以通过DotNet自带的特性来限制自定义的特性。 [AttributeUsage(AttributeTargets.All,AllowMultiple =true,Inherited =false)]

  a:AttributeTargets.All 表示可以加在所有的上面(包括类、属性、接口),也可以根据自己的需求,比如 AttributeTargets.Class 只允许加在类上。

  b:约束该特性能否同时作用于某个元素(类、方法、属性等等)多次,默认为false。

  c:  约束该特性作用于基类(或其它)上,其子类能否继承该特性,默认为true。

 5. 下面自定义一个ypf特性

复制代码

 1     [AttributeUsage(AttributeTargets.All,AllowMultiple =true,Inherited =false)]2     public class ypfAttribute : Attribute3     {4         /// <summary>5         /// 默认的构造函数6         /// </summary>7         public ypfAttribute()8         {9 
10         }
11 
12         /// <summary>
13         /// 新声明的构造函数
14         /// </summary>
15         public ypfAttribute(int id)
16         {
17 
18         }
19         /// <summary>
20         /// 新声明的构造函数
21         /// </summary>
22         public ypfAttribute(int id,string name)
23         {
24 
25         }
26         /// <summary>
27         /// 声明要给属性
28         /// </summary>
29         public string Remark { get; set; }
30 
31         /// <summary>
32         /// 声明一个字段
33         /// </summary>
34         public string Description = null;
35     }

复制代码

 (1).  作用形式

复制代码

 1     /// <summary>2     /// 用户实体类3     /// </summary>5     [ypfAttribute]6     [ypf]7     [ypfAttribute()]8     [ypf()]    //以上四个等价9     [ypf(123)]
10     [ypfAttribute(123)]
11     [ypf(123, "456")]
12     [ypfAttribute(123, "456")]
13     [ypf(Remark = "这里是特性")]
14     [ypf(123, Remark = "这里是特性")]
15     [ypfAttribute(123, Remark = "这里是特性")]
16     [ypf(123, "456", Remark = "这里是特性")]
17     [ypfAttribute(123, "456", Remark = "这里是特性", Description = "Description")]
18 
19     [Table("User")]
20     public class UserModel
21     {
22         /// <summary>
23         /// 主键ID
24         /// </summary>
25         [myValidate(1, 1000)]
26         public int Id { get; set; }
27         /// <summary>
28         /// 账号
29         /// </summary>
30         public string Account { get; set; }
31         /// <summary>
32         /// 密码
33         /// </summary>
34         public string Password { get; set; }
35         /// <summary>
36         /// EMaill
37         /// </summary>
38         public string Email { get; set; }
39 
40     }

复制代码

(2). 如何获取特性中值? (   [ypfAttribute(123, "456", Remark = "这里是特性", Description = "Description")]  )

A.  重新构建ypfAttribute中的内容,需要在该特性内部封装四个获取四个内容的方法

复制代码

 1  [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)]2     public class ypfAttribute : Attribute3     {4         public int _id;5         public string _name;6 7         /// <summary>8         /// 默认的构造函数9         /// </summary>
10         public ypfAttribute()
11         {
12 
13         }
14 
15         /// <summary>
16         /// 新声明的构造函数
17         /// </summary>
18         public ypfAttribute(int id)
19         {
20 
21         }
22         /// <summary>
23         /// 新声明的构造函数
24         /// </summary>
25         public ypfAttribute(int id, string name)
26         {
27             this._id = id;
28             this._name = name;
29         }
30         /// <summary>
31         /// 声明要给属性
32         /// </summary>
33         public string Remark { get; set; }
34 
35         /// <summary>
36         /// 声明一个字段
37         /// </summary>
38         public string Description = null;
39 
40         //下面封装四个方法,分别获取该属性中的内容
41         public int GetOwnId()
42         {
43             return this._id;
44         }
45         public string GetOwnName()
46         {
47             return this._name;
48         }
49         public string GetOwnRemark()
50         {
51             return this.Remark;
52         }
53         public string GetOwnDescription()
54         {
55             return this.Description;
56         }
57     }

复制代码

 B:封装获取特性内容的可供外部调用的方法(在该方法中要调用ypf内部的封装的方法)

 

复制代码

 1          /// <summary>2         /// 根据类型获取自定义特性ypfAttribute中的四个内容3         /// </summary>4         /// <typeparam name="T"></typeparam>5         /// <param name="t"></param>6         public static void GetypfAttributeMsg<T>(this T t) where T : new()7         {8             //1.获取类9             Type type = t.GetType();
10             //2. 获取类中的所有特性
11             object[] attributeList = type.GetCustomAttributes(true);
12             //3. 查找ypf特性
13             foreach (var item in attributeList)
14             {
15                 if (item is ypfAttribute)
16                 {
17                     ypfAttribute ypfattr = item as ypfAttribute;
18                     int id = ypfattr.GetOwnId();
19                     string Name = ypfattr.GetOwnName();
20                     string remark = ypfattr.GetOwnRemark();
21                     string Des = ypfattr.GetOwnDescription();
22                     Console.WriteLine("ypfAttribute上的四个内容分别为:{0},{1},{2},{3}",id,Name,remark,Des);
23                 }
24             }
25         }

复制代码

C. 调用
1  {
2                 //测试获取UserModel类上的ypfAttribute中的四个内容
3                 Console.WriteLine("----------------------测试获取UserModel类上的ypfAttribute中的四个内容--------------------");
4                 UserModel userModel = new UserModel();
5                 userModel.GetypfAttributeMsg();
6   }

D. 结果

 

三. 案例(制作一个验证属性长度的特性)

1. 构建一个myValidateAttribute特性,里面包含校验方法。

复制代码

 1   /// <summary>2     /// 验证int类型属性长度的特性3     /// </summary>4     [AttributeUsage(AttributeTargets.Property)]   //表示该特性只能作用于属性上5     public class myValidateAttribute:Attribute6     {7         private int _min = 0;8         private int _max = 0;9 
10         /// <summary>
11         /// 自定义构造函数
12         /// </summary>
13         /// <param name="min"></param>
14         /// <param name="max"></param>
15         public myValidateAttribute(int min,int max)
16         {
17             this._min = min;
18             this._max = max;
19         }
20         /// <summary>
21         /// 封装校验是否合法的方法
22         /// </summary>
23         /// <param name="num"></param>
24         /// <returns></returns>
25         public bool CheckIsRational(int num)
26         {
27             return num >= this._min && num <= this._max; 
28         }
29     }

复制代码

2. 外部校验方法

复制代码

 1         /// <summary>2         /// 校验并保存的方法3         /// </summary>4         /// <typeparam name="T"></typeparam>5         /// <param name="t"></param>6         public static void Save<T>(T t)7         {8             bool isSafe = true;9             //1. 获取实例t所在的类
10             Type type = t.GetType();
11             //2. type.GetProperties() 获取类中的所有属性
12             foreach (var property in type.GetProperties())
13             {
14                 //3. 获取该属性上的所有特性
15                 object[] attributesList = property.GetCustomAttributes(true);
16                 //4. 找属性中的特性
17                 foreach (var item in attributesList)
18                 {
19                     if (item is myValidateAttribute)
20                     {
21                         myValidateAttribute attribute = item as myValidateAttribute;
22                         //调用特性中的校验方法
23                         //表示获取属性的值:property.GetValue(t)
24                         isSafe = attribute.CheckIsRational((int)property.GetValue(t));
25                     }
26                 }
27                 if (!isSafe)
28                 {
29                     break;
30                 }
31             }
32             if (isSafe)
33             {
34                 Console.WriteLine("保存到数据库");
35             }
36             else
37             {
38                 Console.WriteLine("数据不合法");
39             }
40         }

复制代码

3. 调用

复制代码

1  {
2                 //制作一个可以限制int类型属性长度的特性,并封装对应的校验方法
3                 UserModel userModel = new UserModel();
4                 // userModel.Id = 1000;
5                 userModel.Id = 1001;  // 不合法
6                 BaseDal.Save<UserModel>(userModel);
7  }

复制代码

4. 结果

四. 总结

  自定义特性的使用步骤: 声明特性→特性中封装获取特性参数的方法→将特性作用于对象上→封装外部校验作用对象的方法→调用

  封装外部校验作用对象的方法要用到反射,这里简单补充一下反射在知识:

   反射详见章节:    .Net进阶系列(2)-反射

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

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

相关文章

java不建议用全局变量吗_不要使用全局变量, ThreadLocal也不行

不要使用全局变量的道理大家都懂&#xff0c;基本上在大家学习编程过程中很早就会被教育到&#xff0c;但是有时候我们也会禁不住诱惑用到一些似非实是的全局变量&#xff0c;只不过这些全局变量会穿上马甲&#xff0c;让你不会一下看穿它的巨大危害&#xff0c;这里就讲一下我…

第十二节:Lambda、linq、SQL的相爱相杀(1)

一. 谈情怀 Lambda、Linq、SQL伴随着我的开发一年又一年&#xff0c;但它们三者并没有此消彼长&#xff0c;各自占有这一定的比重&#xff0c;起着不可替代的作用。 相信我们最先接触的应该就是SQL了&#xff0c;凡是科班出身的人&#xff0c;大学期间都会学习SQL Server数据库…

php java 共享session_PHP 实现多服务器共享 SESSION 数据

一、问题起源稍大一些的网站&#xff0c;通常都会有好几个服务器&#xff0c;每个服务器运行着不同功能的模块&#xff0c;使用不同的二级域名&#xff0c;而一个整体性强的网站&#xff0c;用户系统是统一的&#xff0c;即一套用户名、密码在整个网站的各个模块中都是可以登录…

第十三节:Lambda、linq、SQL的相爱相杀(2)

一. Linq开篇 1.Where用法 linq中where的用法与SQL中where的用法基本一致。 1 #region 01-where用法2 {3 //1. where用法4 //1.1 查询账号为admin的用户信息5 Console.WriteLine("------------…

asp 调用java文件上传_用asp实现文件浏览、上传、下载的程序

可以放在服务器上&#xff0c;对服务器上的文件进行浏览、上传、下载&#xff0c;可下载文件源码。把下所有代码入在一个文件里即可&#xff0c;文件的后缀要为asp。thedir request("thedir")if thedir "" thenfolderini server.mappath(".")…

第十四节:Lambda、linq、SQL的相爱相杀(3)

一. SQL 开篇 1. where用法 1    #region 封装EF调用SQL语句查询 2 public static List<T> ExecuteQuery<T>(string sql, params SqlParameter[] pars) 3 { 4 return db.Database.SqlQuery<T>(sql, pars).ToList(); 5 …

hive mysql windows_Java-从MySQL到Hive导入,其中MySQL在Windows上运行,而Hive在Cent OS上运行(Horton Sandbox)...

在任何答案和评论之前.我尝试了在Stackoverflow中找到的几个选项,但均以失败告终.以下是这些链接-我通过命令行在Horton Sandbox中进行了尝试并成功.sqoop import --connect jdbc:mysql://192.168.56.101:3316/database_name --usernameuser --passwordpwd --table table_name …

第十五节:Expression表达式目录树(与委托的区别、自行拼接、总结几类实例间的拷贝)

一. 基本介绍 回忆&#xff1a; 最早接触到表达式目录树(Expression)可能要追溯到几年前使用EF早期的时候&#xff0c;发现where方法里的参数是Expression<Func<T,bool>>这么一个类型&#xff0c;当初不是很理解&#xff0c;只是知道传入lambda表达式使用即可&…

Php7 mongodb explain,【代码片-1】 php7 mongoDB 简单封装

/*** mongoDB 简单 封装* 注意&#xff1a;支持 mongoDB 3.2** author color_wind*/finalclassm_mgdb {privatestatic$ins [];privatestatic$def"default";private$_conn null;private$_db null;privatestatic$_config ["default"> ["url">…

IIS Web 服务器/ASP.NET 运行原理基本知识概念整理

前言&#xff1a; 记录 IIS 相关的笔记还是从公司笔试考核题开始的&#xff0c;问 Application Pool 与 AppDomain 的区别&#xff1f; 促使我对进程池进了知识的学习&#xff0c;所以记录一下学习的笔记。 我们知道现在 .NET 就业来看&#xff0c;80% 的 .NET 程序员都是从事 …

java正则表达式 ascii,是否可以检查字符串是否在Java中仅包含ASCII?

使用正则表达式您可以使用以下正则表达式查找特定的String值是否包含ASCII字符-\\A\\p{ASCII}*\\zString类的matches()方法接受正则表达式&#xff0c;并验证当前字符串是否与给定表达式匹配(如果匹配)&#xff0c;则返回true&#xff0c;否则返回false。因此&#xff0c;通过将…

Http请求处理流程

从一个页面比如www.xuxiaoyu.net的请求开始如何就能打开blogs页面的呢&#xff1f;这其中发生了什么样的东西&#xff1f; Http请求(Http Request) 当服务器&#xff08;IIS&#xff09;接受到一个Http请求的时候进行以下步骤的处理&#xff1a; 1)服务器获取所请求的页面的后缀…

matlab 基金业绩归因,基金专题报告:基于净值和持仓的基金业绩归因方法研究...

核心观点&#xff1a;当前主流的基金业绩归因方法主要有两个方向&#xff1a;一是基于净值数据的时间序列回归方法&#xff0c;所需数据较少且操作简单&#xff0c;主要通过基金历史收益率与风险溢价因子收益率进行回归来分析&#xff0c;二是基于持仓数据的归因方法&#xff0…

iis到w3wp的数据流及工作原理

HTTP.sys->IO线程-CLR线程池中的worker线程处理 IO线程只负责把请求交给Worker线程或者放入进程池级别的队列,然后又去HTTP.SYS的队列中处理其它的请求

php跨域session共享,PHP中利用COOKIE与SESSION联合实现SESSION跨域

大家都知道在一般情况下,一个网站只有一个域名,www.demo.com,但是也有些网站架构是由多个子域名组建的.所以就需要SESSION可以跨子域被 访问到,这样才可以实现用户的跨域登录.就是说客户在A下登录的,同样B也同时登录了,不需要用户再次登录,同时也实现了参数的跨域传递.当然不可…

关于w3wp.exe

一. IIS各版本间的区别 IIS 5.0 IIS 5.1 IIS 6.0 平台 Windows 2000 Windows XP Professional Windows Server 2003 家族 体系结构 32 位 32 位和 64 位 32 位和 64 位 应用程序进程模型 TCP/IP 内核 DLLhost.exe&#xff08;处于中等或高应用程序隔离模式下的多个…

php云解析播放器,xyplay云解析PHPV3.4.1优化稳定版视频解析

演示地址&#xff1a;如有演示站请以演示为准&#xff0c;无演示站以截图为准,源码太多服务器有限&#xff0c;无法搭建所有源码演示站&#xff0c;请谅解&#xff01;新手购买指导&#xff1a;1.在本站注册账号 丨 2.登录已注册账号充值源码所需金币 丨 3.登录账号下载所需源码…

php version.,PHP_VERSION指什么

PHP_VERSION (string)当前的PHP版本&#xff0c;以字符串形式“ major.minor.release [extra]”表示。 (推荐学习&#xff1a;PHP视频教程)例如&#xff1a;<?php // PHP_VERSION_ID 自 PHP 5.2.7 起有效&#xff0c;// 如果我们的版本低于该版本&#xff0c;则用以下代码来…

C# async 和 await 理解

先假设如下场景&#xff1a; 主函数 Main&#xff0c;循环等待用户输入&#xff1b; 计算函数 Cal&#xff0c;耗时计算大量数据&#xff1b; class Test {static int Main(string[] args){while(true){// 等待用户输入}}public static int Cal() {int sum 0;for (int i …

php进阶面向对象及tp5,TP5实战技巧---开发思路 引路造桥

## TP5实战技巧实例---开发思路> 子曰&#xff1a;“学而不思则罔&#xff0c;思而不学则殆。”[TOC]### 利用TP的MVC框架 做快速开发>[success] 写在前面的话:既然选择TP5框架,我推荐大家要通读完全开发手册,我这里并不是要大家记住每一个方法,每一个细节.而是要求大家心…