C# 特性与反射

特性

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

特性(Attribute)用于添加元数据,如编译器指令和注释、描述、方法、类等其他信息。.Net 框架提供了两种类型的特性:*预定义*特性和*自定义*特性。

规定特性(Attribute)

规定特性(Attribute)的语法如下:

[attribute(positional_parameters, name_parameter = value, ...)]
element

特性(Attribute)的名称和值是在方括号内规定的,放置在它所应用的元素之前。positional_parameters 规定必需的信息,name_parameter 规定可选的信息。

预定义特性(Attribute)

.Net 框架提供了三种预定义特性:

  • AttributeUsage
  • Conditional
  • Obsolete
AttributeUsage

预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。

规定该特性的语法如下:

[AttributeUsage(validon,AllowMultiple=allowmultiple,Inherited=inherited
)]

其中:

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

例如:

[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property, 
AllowMultiple = true)]
Conditional

这个预定义特性标记了一个条件方法,其执行依赖于指定的预处理标识符。

它会引起方法调用的条件编译,取决于指定的值,比如 Debug 或 Trace。例如,当调试代码时显示变量的值。

规定该特性的语法如下:

[Conditional(conditionalSymbol
)]

例如:

[Conditional("DEBUG")]

下面的实例演示了该特性:
实例

#define DEBUG
using System;
using System.Diagnostics;
public class Myclass
{[Conditional("DEBUG")]public static void Message(string msg){Console.WriteLine(msg);}
}
class Test
{static void function1(){Myclass.Message("In Function 1.");function2();}static void function2(){Myclass.Message("In Function 2.");}public static void Main(){Myclass.Message("In Main function.");function1();Console.ReadKey();}
}

当上面的代码被编译和执行时,它会产生下列结果:

In Main function
In Function 1
In Function 2
Obsolete

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

规定该特性的语法如下:

[Obsolete(message
)]
[Obsolete(message,iserror
)]

其中:

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

下面的实例演示了该特性:
实例

using System;
public class MyClass
{[Obsolete("Don't use OldMethod, use NewMethod instead", true)]static void OldMethod(){ Console.WriteLine("It is the old method");}static void NewMethod(){ Console.WriteLine("It is the new method"); }public static void Main(){OldMethod();}
}

当您尝试编译该程序时,编译器会给出一个错误消息说明:

Don't use OldMethod, use NewMethod instead

创建自定义特性(Attribute)

.Net 框架允许创建自定义特性,用于存储声明性的信息,且可在运行时被检索。该信息根据设计标准和应用程序需要,可与任何目标元素相关。

创建并使用自定义特性包含四个步骤:

  • 声明自定义特性
  • 构建自定义特性
  • 在目标程序元素上应用自定义特性
  • 通过反射访问特性

最后一个步骤包含编写一个简单的程序来读取元数据以便查找各种符号。元数据是用于描述其他数据的数据和信息。该程序应使用反射来在运行时访问特性。我们将在下一章详细讨论这点。

声明自定义特性

一个新的自定义特性应派生自 System.Attribute 类。例如:

// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]public class DeBugInfo : System.Attribute

在上面的代码中,我们已经声明了一个名为 DeBugInfo 的自定义特性。

构建自定义特性

让我们构建一个名为 DeBugInfo 的自定义特性,该特性将存储调试程序获得的信息。它存储下面的信息:

  • bug 的代码编号
  • 辨认该 bug 的开发人员名字
  • 最后一次审查该代码的日期
  • 一个存储了开发人员标记的字符串消息

我们的 DeBugInfo 类将带有三个用于存储前三个信息的私有属性(property)和一个用于存储消息的公有属性(property)。所以 bug 编号、开发人员名字和审查日期将是 DeBugInfo 类的必需的定位( positional)参数,消息将是一个可选的命名(named)参数。

每个特性必须至少有一个构造函数。必需的定位( positional)参数应通过构造函数传递。下面的代码演示了 DeBugInfo 类:
实例

// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]public class DeBugInfo : System.Attribute
{private int bugNo;private string developer;private string lastReview;public string message;public DeBugInfo(int bg, string dev, string d){this.bugNo = bg;this.developer = dev;this.lastReview = d;}public int BugNo{get{return bugNo;}}public string Developer{get{return developer;}}public string LastReview{get{return lastReview;}}public string Message{get{return message;}set{message = value;}}
}
应用自定义特性

通过把特性放置在紧接着它的目标之前,来应用该特性:
实例

[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
class Rectangle
{// 成员变量protected double length;protected double width;public Rectangle(double l, double w){length = l;width = w;}[DeBugInfo(55, "Zara Ali", "19/10/2012",Message = "Return type mismatch")]public double GetArea(){return length * width;}[DeBugInfo(56, "Zara Ali", "19/10/2012")]public void Display(){Console.WriteLine("Length: {0}", length);Console.WriteLine("Width: {0}", width);Console.WriteLine("Area: {0}", GetArea());}
}

反射

C# 反射(Reflection)

反射指程序可以访问、检测和修改它本身状态或行为的一种能力。

程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。

您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。

优缺点

优点:

  • 1、反射提高了程序的灵活性和扩展性。
  • 2、降低耦合性,提高自适应能力。
  • 3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。

缺点:

  • 1、性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
  • 2、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。

反射(Reflection)的用途

反射(Reflection)有下列用途:

  • 它允许在运行时查看特性(attribute)信息。
  • 它允许审查集合中的各种类型,以及实例化这些类型。
  • 它允许延迟绑定的方法和属性(property)。
  • 它允许在运行时创建新类型,然后使用这些类型执行一些任务。

查看元数据

我们已经在上面的章节中提到过,使用反射(Reflection)可以查看特性(attribute)信息。

System.Reflection 类的 MemberInfo 对象需要被初始化,用于发现与类相关的特性(attribute)。为了做到这点,您可以定义目标类的一个对象,如下:

System.Reflection.MemberInfo info = typeof(MyClass);

C#

下面的程序演示了这点:

实例

using System;[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute
{public readonly string Url;public string Topic  // Topic 是一个命名(named)参数{get{return topic;}set{topic = value;}}public HelpAttribute(string url)  // url 是一个定位(positional)参数{this.Url = url;}private string topic;
}
[HelpAttribute("Information on the class MyClass")]
class MyClass
{
}namespace AttributeAppl
{class Program{static void Main(string[] args){System.Reflection.MemberInfo info = typeof(MyClass);object[] attributes = info.GetCustomAttributes(true);for (int i = 0; i < attributes.Length; i++){System.Console.WriteLine(attributes[i]);}Console.ReadKey();}}
}

C#

当上面的代码被编译和执行时,它会显示附加到类 MyClass 上的自定义特性:

HelpAttribute

C#

实例

在本实例中,我们将使用在上一章中创建的 DeBugInfo 特性,并使用反射(Reflection)来读取 Rectangle 类中的元数据。

实例

using System;
using System.Reflection;
namespace BugFixApplication
{// 一个自定义特性 BugFix 被赋给类及其成员[AttributeUsage(AttributeTargets.Class |AttributeTargets.Constructor |AttributeTargets.Field |AttributeTargets.Method |AttributeTargets.Property,AllowMultiple = true)]public class DeBugInfo : System.Attribute{private int bugNo;private string developer;private string lastReview;public string message;public DeBugInfo(int bg, string dev, string d){this.bugNo = bg;this.developer = dev;this.lastReview = d;}public int BugNo{get{return bugNo;}}public string Developer{get{return developer;}}public string LastReview{get{return lastReview;}}public string Message{get{return message;}set{message = value;}}}[DeBugInfo(45, "Zara Ali", "12/8/2012",Message = "Return type mismatch")][DeBugInfo(49, "Nuha Ali", "10/10/2012",Message = "Unused variable")]class Rectangle{// 成员变量protected double length;protected double width;public Rectangle(double l, double w){length = l;width = w;}[DeBugInfo(55, "Zara Ali", "19/10/2012",Message = "Return type mismatch")]public double GetArea(){return length * width;}[DeBugInfo(56, "Zara Ali", "19/10/2012")]public void Display(){Console.WriteLine("Length: {0}", length);Console.WriteLine("Width: {0}", width);Console.WriteLine("Area: {0}", GetArea());}}//end class Rectangle  class ExecuteRectangle{static void Main(string[] args){Rectangle r = new Rectangle(4.5, 7.5);r.Display();Type type = typeof(Rectangle);// 遍历 Rectangle 类的特性foreach (Object attributes in type.GetCustomAttributes(false)){DeBugInfo dbi = (DeBugInfo)attributes;if (null != dbi){Console.WriteLine("Bug no: {0}", dbi.BugNo);Console.WriteLine("Developer: {0}", dbi.Developer);Console.WriteLine("Last Reviewed: {0}",dbi.LastReview);Console.WriteLine("Remarks: {0}", dbi.Message);}}// 遍历方法特性foreach (MethodInfo m in type.GetMethods()){foreach (Attribute a in m.GetCustomAttributes(true)){DeBugInfo dbi = (DeBugInfo)a;if (null != dbi){Console.WriteLine("Bug no: {0}, for Method: {1}",dbi.BugNo, m.Name);Console.WriteLine("Developer: {0}", dbi.Developer);Console.WriteLine("Last Reviewed: {0}",dbi.LastReview);Console.WriteLine("Remarks: {0}", dbi.Message);}}}Console.ReadLine();}}
}

C#

当上面的代码被编译和执行时,它会产生下列结果:

Length: 4.5
Width: 7.5
Area: 33.75
Bug No: 49
Developer: Nuha Ali
Last Reviewed: 10/10/2012
Remarks: Unused variable
Bug No: 45
Developer: Zara Ali
Last Reviewed: 12/8/2012
Remarks: Return type mismatch
Bug No: 55, for Method: GetArea
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: Return type mismatch
Bug No: 56, for Method: Display
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks:

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

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

相关文章

【SQL Server】华中农业大学空间数据库实验报告 实验三 数据操作

1.实验目的 熟悉了解掌握SQL Server软件的基本操作与使用方法&#xff0c;以及通过理论课学习与实验参考书的帮助&#xff0c;熟练掌握使用T-SQL语句和交互式方法对数据表进行插入数据、修改数据、删除数据等等的操作&#xff1b;作为后续实验的基础&#xff0c;根据实验要求重…

LDR6020驱动的Type-C接口显示器解决方案

一、引言 随着科技的飞速发展&#xff0c;Type-C接口凭借其高速数据传输、强大的电力传输能力以及便捷的正反可插设计&#xff0c;正逐渐成为现代电子设备的主流接口标准。在显示器领域&#xff0c;Type-C接口的引入不仅简化了线缆连接&#xff0c;还为用户带来了更丰富的功能…

Spring |(四)IoC/DI配置管理第三方bean

文章目录 &#x1f4da;数据源对象管理&#x1f407;环境准备&#x1f407;实现Druid管理&#x1f407;实现C3P0管理 &#x1f4da;加载properties文件&#x1f407;第三方bean属性优化&#x1f407;读取单个属性 学习来源&#xff1a;黑马程序员SSM框架教程_SpringSpringMVCMa…

三十一、构建完善微服务——API 网关

一、API 网关基础 系统拆分为微服务后&#xff0c;内部的微服务之间是互联互通的&#xff0c;相互之间的访问都是点对点的。如果外部系统想调用系统的某个功能&#xff0c;也采取点对点的方式&#xff0c;则外部系统会非常“头大”。因为在外部系统看来&#xff0c;它不需要也没…

(免费送源码)计算机毕业设计原创定制:Java+JSP+HTML+JQUERY+AJAX+MySQL springboot计算机类专业考研学习网站管理系统

摘 要 大数据时代下&#xff0c;数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化安全的要求&#xff0c;利用互联网服务于其他行业&#xff0c;促进生产&#xff0c;已经是成为一种势不可挡的趋势。在大学生在线计算机类专业考研学习网站管理的要求下&#xff0c;开发一…

社交电商专业赋能高校教育与产业协同发展:定制开发AI智能名片及2+1链动商城小程序的创新驱动

摘要&#xff1a;本文围绕社交电商有望成为高校常态专业这一趋势展开深入探讨&#xff0c;剖析国家政策认可下其学科发展前景&#xff0c;着重阐述在专业建设进程中面临的师资短缺及实践教学难题。通过引入定制开发AI智能名片与21链动商城小程序&#xff0c;探究如何借助这些新…

Linux各种并发服务器优缺点

本文旨在介绍针对“无并发C/S模型”改进的方法总结以及各种改进方法的优缺点&#xff0c;具体函数的实现并不介绍。 1. 无并发C/S模型 创建服务器流程分析&#xff1a; socket()创建服务器的监听套接字bind()将服务器给服务器的监听套接字绑定IP地址和Port端口号listen()设置…

基于AXI PCIE IP的FPGA PCIE卡示意图

创作不易&#xff0c;转载请注明出处&#xff1a;https://blog.csdn.net/csdn_gddf102384398/article/details/143926217 上图中&#xff0c;在FPGA PCIE卡示意图内&#xff0c;有2个AXI Master设备&#xff0c;即&#xff1a;PCIE到AXI4-Full-Master桥、AXI CDMA IP&#xff1…

【漏洞复现】|智互联SRM智联云采系统quickReceiptDetail SQL注入漏洞

漏洞描述 智互联(深圳)科技有限公司SRM智联云采系统针对企业供应链管理难题&#xff0c;及智能化转型升级需求&#xff0c;智联云采依托人工智能、物联网、大数据、云等技术&#xff0c;通过软硬件系统化方案&#xff0c;帮助企业实现供应商关系管理和采购线上化、移动化、智能…

el-table-column自动生成序号在序号前插入图标

实现效果&#xff1a; 代码如下&#xff1a; 在el-table里加入这个就可以了&#xff0c;需要拿到值可以用scope.$index ​​​​​​​<el-table-column type"index" label"序号" show-overflow-tooltip"true" min-width"40">…

如何利用 Puppeteer 的 Evaluate 函数操作网页数据

介绍 在现代的爬虫技术中&#xff0c;Puppeteer 因其强大的功能和灵活性而备受青睐。Puppeteer 是一个用于控制 Chromium 或 Chrome 浏览器的 Node.js 库&#xff0c;提供了丰富的 API 接口&#xff0c;能够帮助开发者高效地处理动态网页数据。本文将重点讲解 Puppeteer 的 ev…

“小浣熊家族AI办公助手”产品体验 — “人人都是数据分析师”

一、引言&#xff1a; 大家平时应该在工作中常常使用到Excel来做数据统计&#xff0c;比如临近过年时&#xff0c;公司一般会开各种复盘、年终、检讨、明年规划大会&#xff0c;势必需要准备一大堆的量化数据报表&#xff0c;用于会议上的数据汇报、分析工作&#xff0c;试想一…

Unity-添加世界坐标系辅助线

如果你想在场景中更直观地显示世界坐标系&#xff0c;可以通过编写一个简单的脚本来实现。下面是一个基本的示例脚本&#xff0c;它会在场景中绘制出世界坐标系的三个轴&#xff1a; using UnityEngine;public class WorldAxesIndicator : MonoBehaviour {public float length…

Makefile基础应用

1 使用场景 在Linux环境下&#xff0c;我们通常需要通过命令行来编译代码。例如&#xff0c;在使用gcc编译C语言代码时&#xff0c;需要使用以下命令。 gcc -o main main.c 使用这种方式编译代码非常吃力&#xff0c;每次调试代码都需要重新在命令行下重新编译&#xff0c;重复…

【tensorflow的安装步骤】

创建一个虚拟环境 conda create -n tensorflow python3.6激活虚拟环境 conda activate tensorflow使用镜像源下载 pip install tensorflow1.15.0 -i https://pypi.tuna.tsinghua.edu.cn/simple/特别特别重要的点&#xff01;&#xff01;&#xff01; 别用WiFi或者校园网下…

【Python · PyTorch】循环神经网络 RNN(基础概念)

【Python PyTorch】循环神经网络 RNN&#xff08;基础概念&#xff09; 0. 生物学相似性1. 概念2. 延时神经网络&#xff08;TDNN&#xff09;3. 简单循环神经网络&#xff08;Simple RNN&#xff09;3.1 BiRNN 双向循环神经网络3.2 特点记忆性参数共享图灵完备 3.3 网络结构3…

使用EFK收集k8s日志

首先我们使用EFK收集Kubernetes集群中的日志&#xff0c;本次实验讲解的是在Kubernetes集群中启动一个Elasticsearch集群&#xff0c;如果企业内已经有了Elasticsearch集群&#xff0c;可以直接将日志输出至已有的Elasticsearch集群。 文章目录 部署elasticsearch创建Kibana创建…

Qt入门1——认识Qt的几个常用头文件和常用函数

1.头文件 ① #include <QPushButton>——“按钮”头文件&#xff1b; ② #include <QLabel>——“标签”头文件&#xff1b; ③ #include <QFont>——“字体”头文件&#xff1b; ④#include <QDebug>——输出相关信息&#xff1b; 2. 常用函数/类的基…

【Linux驱动开发】irq中断配置API及中断应用 阻塞休眠和非阻塞的驱动操作

【Linux驱动开发】irq中断配置API及中断应用 阻塞休眠和非阻塞的驱动操作 文章目录 中断操作注册和释放中断中断服务函数使能和禁止上半部和下半部软中断tasklet工作队列 设备节点中的中断中断号API函数获取中断号获取中断信息 中断应用读取设备树节点获取中断号获取中断触发方…

Linux设置以及软件的安装(hadoop集群安装02)

一、Linux的常见设置 1、设置静态IP vi /etc/sysconfig/network-scripts/ifcfg-ens33 如何查看自己的虚拟机的网关&#xff1a; 完整的配置&#xff08;不要拷贝我的&#xff09;&#xff1a; TYPE"Ethernet" PROXY_METHOD"none" BROWSER_ONLY"no&…