C#高级语法 Attribute特性详解和类型,方法,变量附加特性讲解

前言

Attribute特性是一种高级的语法,在C#和Java中用的比较多。如果你想要了解特性,就需要先了解反射。

相关资料

【C#进阶】C# 特性

C# 官方文档 创建自定义特性

C# 官方文档 使用反射访问特性

C#基础教程 Attribute 特性与反射案例详解,自动化识别与使用类型!

C#基础教程 Reflection应用,简单使用反射,打破常规!

Attribute特性

Attribute是一个简单的语法,一般来说都是放在类/变量/函数的前面,当然也可以放在参数里面。不过我们这里主要讨论常用的三种情况:

  • 变量
  • 方法

个人原理理解

找到带有Attribute特性的类
Assembly程序集,存放所有的编译信息
所有的Class类名
带有Attribute特性的类
Type
Attribute特性
...等等
MethodInfo方法属性
Attribute
PropertyInfo变量属性

特性的声明与使用

【C#进阶】C# 特性

在这里插入图片描述

简单的特性声明

namespace NetCore.Models
{/// <summary>/// 特性需要以MyAttributeTestAttribute结尾,这个是约定/// </summary>[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]public class MyAttributeTestAttribute:Attribute{public int Id { get; set; }public string Name { get; set; }public MyAttributeTestAttribute(string name) {Name = name;}public MyAttributeTestAttribute(){}}
}

在这里插入图片描述

为了方便后面的讲解,我们这里声明三个特性

namespace NetCore.Models
{/// <summary>/// 类型特性/// </summary>[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]public class MyClassAttribute:Attribute{public string Name { get; set; }public MyClassAttribute(string name) {Name = name;}public MyClassAttribute() { }}
}
namespace NetCore.Models
{/// <summary>/// 方法特性/// </summary>[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]public class MyMethodAttribute:Attribute{public string Name { get; set; }public MyMethodAttribute(string name) {Name = name;}public MyMethodAttribute() { }}
}
namespace NetCore.Models
{/// <summary>/// 参数特性/// </summary>[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]public class MyPropertyAttribute:Attribute{public string Name { get; set; }public MyPropertyAttribute(string name) {Name = name;}public MyPropertyAttribute() { }}
}

类型特性

我们声明三个类,去获取这三个类的MyClass特性
其它两个设置差不多

在这里插入图片描述
在这里插入图片描述

  static void Main(string[] args){var list = GetAllTypes<MyClassAttribute>();for (var i = 0; i < list.Count; i++){Console.WriteLine($"ClassName:[{list[i].Name}],Attribute.Name[{GetAttribute<MyClassAttribute>(list[i]).Name}]");}Console.WriteLine("运行完成!");Console.ReadKey();}/// <summary>/// 获取所有有T特性的类型/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public static List<Type> GetAllTypes<T>() where T : Attribute{var res = new List<Type>();//Assembly存放所有的程序集res = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.GetCustomAttributes(typeof(T), false).Any())//我们找到所有程序集中带有T特性的Type类型.ToList();return res;}/// <summary>/// 获取/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(Type model) where T : Attribute, new(){var res = new T();res = model.GetCustomAttribute<T>();return res;}

运行结果:

在这里插入图片描述

找到类的Attribute属性

如果只是找到带有Attribute的属性,那么意义就不大了,那么目前就只有一个标记的功能。这里我们将对应Attribute属性取到

 static void Main(string[] args){var list = GetAllTypes<MyClassAttribute>();for (var i = 0; i < list.Count; i++){Console.WriteLine($"ClassName:[{list[i].Name}],Attribute.Name[{GetAttribute<MyClassAttribute>(list[i]).Name}]");}Console.WriteLine("运行完成!");Console.ReadKey();}/// <summary>/// 获取所有有T特性的类型/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public static List<Type> GetAllTypes<T>() where T : Attribute{var res = new List<Type>();//Assembly存放所有的程序集res = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.GetCustomAttributes(typeof(T), false).Any())//我们找到所有程序集中带有T特性的Type类型.ToList();return res;}/// <summary>/// 获取/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(Type model) where T : Attribute, new(){var res = new T();res = model.GetCustomAttribute<T>();return res;}

在这里插入图片描述

方法特性和变量特性

现在会了类型特性,那么方法特性和变量特性也差不多了。我们这里直接将对应的代码封装一下

代码封装

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;namespace NetCore.Utils
{public static class MyAttributeHelper{/// <summary>/// 获取该类型下所有的带Attribute的方法/// </summary>/// <typeparam name="T"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<MethodInfo> GetAllMethods<T>(Type type) where T : class, new(){var res = new List<MethodInfo>();res = type.GetMethods().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();return res;}/// <summary>/// 获取该类型下所有的带Attribute的属性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<PropertyInfo> GetAllPropertys<T>(Type type) where T : class, new(){var res = new List<PropertyInfo>();res = type.GetProperties().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();return res;}/// <summary>/// 获取程序集所有有T特性的类型class/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public static List<Type> GetAllTypes<T>() where T : Attribute{var res = new List<Type>();//Assembly存放所有的程序集res = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.GetCustomAttributes(typeof(T), false).Any())//我们找到所有程序集中带有T特性的Type类型.ToList();return res;}/// <summary>/// 获取特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(Type type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 获取特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(MethodInfo type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 获取特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(PropertyInfo type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}}
}

测试类

TestService1

namespace NetCore.Services
{[MyClass("TestServiceAttribute1")]public class TestService1{[MyProperty("TestService1的Property")]public string Name { get; set; }public int Id { get; set; }[MyMethod("TestService1的Method")]public void Test(){}public void Send(){}}
}
TestService2
using NetCore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace NetCore.Services
{[MyClass("TestServiceAttribute2")]public class TestService2{}
}
TestService3
using NetCore.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace NetCore.Services
{[MyClass("TestServiceAttribute3")]public class TestService3{}
}

测试代码

static void Main(string[] args){//找到所有带MyClassAttribute特性的类var list = MyAttributeHelper.GetAllTypes<MyClassAttribute>();for (var i = 0; i < list.Count; i++){Console.WriteLine($"ClassName:[{list[i].Name}],Attribute.Name[{MyAttributeHelper.GetAttribute<MyClassAttribute>(list[i]).Name}]");//找到所有带MyMethodAttribute的方法var methods = MyAttributeHelper.GetAllMethods<MyMethodAttribute>(list[i]);//找到所有带MyPropertyAttribute的方法var propertis = MyAttributeHelper.GetAllPropertys<MyPropertyAttribute>(list[i]);//对代码进行打印foreach (var item in methods){var att = MyAttributeHelper.GetAttribute<MyMethodAttribute>(item);Console.WriteLine($"ClassName:[{list[i].Name}],Method:[{item.Name}],Attribute.Name[{att.Name}]");}foreach (var item in propertis){var att = MyAttributeHelper.GetAttribute<MyPropertyAttribute>(item);Console.WriteLine($"ClassName:[{list[i].Name}],Property:[{item.Name}],Attribute.Name[{att.Name}]");}}Console.WriteLine("运行完成!");Console.ReadKey();}

运行结果

在这里插入图片描述

对封装的代码进行优化

我们获取带有Attribute的类的时候,肯定希望一个函数直接返回两个结果:

  • Type:那个带Attribute的类
  • Attribute:Attribute本身的属性

一个函数返回多个变量有许多种解决方案,我这里觉得使用ValueTuple更加的合适。

C# 元祖,最佳的临时变量。

封装代码

......其它代码/// <summary>/// 返回带有Attribute的类型元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <returns></returns>public static List<(Type type, Att att)> GetAll_TypeAndAtt<Att>() where Att : Attribute, new(){var res = new List<(Type type, Att att)> ();var typeLists = GetAllTypes<Att>();foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att));   }return res;}/// <summary>/// 返回带有Attribute的变量元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<(PropertyInfo property, Att att)> GetAll_PropertyAndAtt<Att>(Type type) where Att : Attribute, new(){var res = new List<(PropertyInfo type, Att att)>();var typeLists = GetAllPropertys<Att>(type);foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att));}return res;}/// <summary>/// 返回带有Attribute的方法元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<(MethodInfo method, Att att)> GetAll_MethodAndAtt<Att>(Type type) where Att : Attribute, new(){var res = new List<(MethodInfo type, Att att)>();var typeLists = GetAllMethods<Att>(type);foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att));}return res;}

测试代码

var lists = MyAttributeHelper.GetAll_TypeAndAtt<MyClassAttribute>();lists.ForEach(item1 =>{Console.WriteLine($"ClassName:[{item1.type.Name}],Attribute.Name[{item1.att.Name}]");var methods = MyAttributeHelper.GetAll_MethodAndAtt<MyMethodAttribute>(item1.type);var properties = MyAttributeHelper.GetAll_PropertyAndAtt<MyPropertyAttribute>(item1.type);methods.ForEach(item2 => { Console.WriteLine($"ClassName:[{item1.type.Name}],Method:[{item2.method.Name}],Attribute.Name[{item2.att.Name}]"); });properties.ForEach(item2 => { Console.WriteLine($"ClassName:[{item1.type.Name}],Method:[{item2.property.Name}],Attribute.Name[{item2.att.Name}]"); });});

运行结果(和上次的一致)

在这里插入图片描述

最后封装好的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;namespace NetCore.Utils
{public static class MyAttributeHelper{/// <summary>/// 获取该类型下所有的带Attribute的方法/// </summary>/// <typeparam name="T"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<MethodInfo> GetAllMethods<T>(Type type) where T : class, new(){var res = new List<MethodInfo>();res = type.GetMethods().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();return res;}/// <summary>/// 获取该类型下所有的带Attribute的属性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<PropertyInfo> GetAllPropertys<T>(Type type) where T : class, new(){var res = new List<PropertyInfo>();res = type.GetProperties().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();return res;}/// <summary>/// 获取程序集所有有T特性的类型class/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public static List<Type> GetAllTypes<T>() where T : Attribute{var res = new List<Type>();//Assembly存放所有的程序集res = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.GetCustomAttributes(typeof(T), false).Any())//我们找到所有程序集中带有T特性的Type类型.ToList();return res;}/// <summary>/// 获取特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(Type type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 获取特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(MethodInfo type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 获取特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(PropertyInfo type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 返回带有Attribute的类型元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <returns></returns>public static List<(Type type, Att att)> GetAll_TypeAndAtt<Att>() where Att : Attribute, new(){var res = new List<(Type type, Att att)> ();var typeLists = GetAllTypes<Att>();foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att));   }return res;}/// <summary>/// 返回带有Attribute的变量元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<(PropertyInfo property, Att att)> GetAll_PropertyAndAtt<Att>(Type type) where Att : Attribute, new(){var res = new List<(PropertyInfo type, Att att)>();var typeLists = GetAllPropertys<Att>(type);foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att));}return res;}/// <summary>/// 返回带有Attribute的方法元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<(MethodInfo method, Att att)> GetAll_MethodAndAtt<Att>(Type type) where Att : Attribute, new(){var res = new List<(MethodInfo type, Att att)>();var typeLists = GetAllMethods<Att>(type);foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att));}return res;}}
}

总结

Attribute是C# 的高级语法,使用范围很广,可以极大的简化我们需要运行代码。本篇文章只是讲解了如何拿到特性属性,如果我们需要深入解决,那么就需要深入了解反射的使用方法。

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

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

相关文章

66、python - 代码仓库介绍

上一节,我们可以用自己手写的算法以及手动搭建的神经网络完成预测了,不知各位同学有没有自己尝试来预测一只猫或者一只狗,看看准确度如何? 本节应一位同学的建议,来介绍下 python 代码仓库的目录结构,以及每一部分是做什么? 我们这个小课的代码实战仓库链接为:cv_lea…

mysql中使用IN的注意事项

目录 前言注意事项 前言 在写sql语句过程中&#xff0c;难免会使用IN条件查询&#xff0c;那你知道使用IN要注意那些事项呢?下面我们就来一列举 注意事项 使用IN查询是否会使用索引 答&#xff1a;有时会使用&#xff0c;有时就不会使用。当IN 的范围小时会使用索引查询&…

MongDB集群部署和升级方案

******集群部署部分****** 主机信息mongodb集群 192.168.1.46 192.168.1.47 192.168.1.48 192.168.1.49 192.168.1.50 192.168.1.51 规划 sharding 1 192.168.1.46 192.168.1.47 192.168.1.48 端口 28111 sharding 2 192.168.1.49 192.168.1.50 192…

JavaScript与Swift的异同,python像vb6

其实很多主流的编程语言都是大同小异,魔改了一下罢了。 JavaScript与Swift一样&#xff0c;是动态语言类型&#xff0c;即不用指定变量类型&#xff0c;会根据赋值的内容动态的判断出它的类型。与Swift不同的是&#xff0c;JavaScript定义变量的时候&#xff0c;也不需要指定变…

【已解决】c语言为什么函数运算顺序从右往左

本博文主要源于笔者正在调试的c程序&#xff0c;c语言的函数运算顺序一直是从右往左int a 5;add(a,a);如果按照正常思维就是(5,5),运行结果确是(6,5),这是为什么呢 问题起源 对c语言的函数运算顺序产生怀疑 问题解释原因 函数从右到左依次入栈&#xff0c;出栈时可以很方便…

12.1SPI驱动框架

SPI硬件基础 总线拓扑结构 引脚含义 DO(MOSI)&#xff1a;Master Output, Slave Input&#xff0c; SPI主控用来发出数据&#xff0c;SPI从设备用来接收数据 DI(MISO) &#xff1a;Master Input, Slave Output&#xff0c; SPI主控用来发出数据&#xff0c;SPI从设备用来接收…

SpringMVC配置文件上传解析器实现文件上传项目实例

SpringMVC配置文件上传解析器实现文件上传项目实例 1、在pom.xml文件中添加相关依赖 <!--文件上传--> <dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.1</versio…

threejs 光带扩散动画

目录 一、创建光带 (1) 设置光带顶点 (2) 设置光带顶点透明度属性 二、光带动画 完整代码 html文件代码 js文件代码 最后展示一下项目里的效果&#xff1a; 最近项目中要求做一段光带效果动画&#xff0c;尝试着写了一下&#xff0c;下面是本次分享光带扩散动画的效果预…

C++11之智能指针

C11之智能指针 前言1、智能指针概念2. 智能指针的定义和使用2.1 auto_ptr&#xff08;C11已经抛弃&#xff09;2.2 share_ptr2.3 unique_ptr2.4 weak_ptr 前言 C程序设计中&#xff0c;动态内存的管理式通过一对运算符来完成的&#xff1a;new和delete。 使用堆内存是非常频繁…

代码随想录算法训练营第一天|数组理论基础、704二分查找、27移除元素

数组理论基础 一维数组 数组中的元素在内存空间中是连续的数组名与数组中第一个元素的地址相同&#xff08;一维数组&#xff09;数组的下标从0开始删除数组的元素其实是用后面的元素覆盖掉要删除的元素数组的长度不能改变 二维数组 二维数组是按照行存储的&#xff0c;也是…

关于json.dumps()写入文件时是utf8

json.dumps()默认情况下&#xff0c;该函数会自动处理Unicode编码。 不要直接在json.dumps()设置encodingutf-8&#xff0c;会报错 json.dumps got an unexpected keyword argument encoding 需要将json.dumps()中设置ensure_asciiFalse&#xff0c;结合open函数中的encodin…

Java解析第三方接口返回的json

在实际开发过程中&#xff0c;免不了和其他公司进行联调&#xff0c;调用第三方接口&#xff0c;这个时候我们就需要根据对方返回的数据进行解析&#xff0c;获得我们想要的字段 第一种 //这种是data里面有个list的格式 {"data": {"username": "s…

linux 网络设备驱动之报文接收

从网络上接收报文比发送它要难一些, 因为必须分配一个 sk_buff 并从一个原子性上下 文中递交给上层. 网络驱动可以实现 2 种报文接收的模式: 中断驱动和查询. 大部分驱 动采用中断驱动技术, 这是我们首先要涉及的. 有些高带宽适配卡的驱动也可能采用查询 技术; 我们在"接收…

Kali Linux——aircrack-ng无线教程

目录 一、准备 二、案例 1、连接usb无线网卡 2、查看网卡信息 3、开启网卡监听 4、扫描wifi信号 5、抓取握手包 6、强制断开连接 7、破解握手包 三、预防 一、准备 1、usb无线网卡&#xff08;笔记本也是需要用到&#xff09; 2、密码字典&#xff08;Kali 系统自带…

java句柄数过多解决办法

java句柄数过多解决办法 使用file-leak-detector指定为应用程序的javaagent&#xff0c;然后重启程序&#xff0c;通过file-leak-detector提供能力&#xff0c;可以查看句柄和线程名称的信息&#xff0c;可直接排查出是哪行代码问题 包下载地址&#xff1a;http://search.mav…

项目整体管理

整体管理之10大项目管理&#xff1a; 核心域&#xff1a;进度&#xff0c;成本&#xff0c;质量&#xff0c;范围 辅助域&#xff1a;风险&#xff0c;沟通&#xff0c;采购&#xff0c;人力资源&#xff0c;干系人 项目管理相关方&#xff1a; 招标&#xff1a;买方&#x…

Acrel-5000重点用能单位能耗在线监测系统的实际应用分析-安科瑞 蒋静

摘要&#xff1a;根据《重点用能节能办法》&#xff08;国家发展改革委等第七部委2018年15号令&#xff09;、《重点用能单位能耗在线监测系统推广建设工作方案》&#xff08;发改环资[2017]1711号&#xff09;和《关于加速推进重点用能单位能耗在线监测系统建设的通知》&#…

评估LLM在细胞数据上的实用性(1)-基本概述

基于LLM的基础模型在工业和科学领域都取得了重大进展。本报告通过八个与单细胞数据相关的下游任务的综合实验&#xff0c;评估了LLM在单细胞测序数据分析中的性能。通过将七种不同的单细胞LLM与特定任务下的baselines进行比较&#xff0c;结果发现单细胞LLMs在所有任务中可能并…

Js-基础语法(二)

运算符 赋值运算符 赋值运算符&#xff1a;对变量进行赋值的运算符 已经学过的赋值运算符&#xff1a; 将等号右边的值赋予给左边, 要求左边必须是一个容器 其他赋值运算符&#xff1a; - */% 使用这些运算符可以在对变量赋值时进行快速操作 一元运算符 众多的 JavaScrip…

固定翼仿真的切换

delta固定翼飞行器模型 接着这篇文章文章链接&#xff0c;我们对飞行器模型进行改进&#xff0c; 我们知道&#xff0c;我们打开仿真模型 gazebo --verbose zephyr_ardupilot_demo.world 我们注意这最后一个语句 <model name"zephyr_delta_wing_demo">//加载z…