C# 特性(一)——什么是特性

news2024/10/7 14:30:06

目录

什么是特性

Serializable

DllImport

Obsolete

Conditional

Attribute类

自定义特性

AttributeUsage的使用例子


特性非常常见,官方解释为:

特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。

我们直接通过实例来理解究竟什么是特性。

什么是特性

Serializable

首先,当一个类需要支持序列化时,我们总能看到类名上方有如下的结构:

[Serializable]
class SampleClass
{
	// ...
}

[Serializable]就是用来标识当前类是否可序列化的。

DllImport

用来标记非.NET的函数,表明该方法在一个外部的DLL中定义。

 [DllImport("User32.dll")]
      public static extern int MessageBox(int hParent, string Message, string Caption, int Type);

 这段代码中        [DllImport]表明了MessageBox是User32.DLL中的函数,这样我们就可以像内部方法一样调用这个函数。

Obsolete

当我们的程序在迭代过程中出现了一些打算弃用的方法,如果直接删除的话,势必会影响到版本的兼容性。因此需要添加一个标识,让开发者注意到这个方法已经弃用,在未来的版本中可能会被删除。这就需要用到[Obsolete]特性:

        [Obsolete("这是需要提示的内容",true)]
        public class Test
        {

        }

当我们的程序在迭代过程中出现了一些打算弃用的方法,如果直接删除的话,势必会影响到版本的兼容性。因此需要添加一个标识,让开发者注意到这个方法已经弃用,在未来的版本中可能会被删除。这就需要用到[Obsolete]特性:

这样在调用被[Obsolete(string,bool)]标记的方法,当bool类型为true时,编译器就会进行提示并报错:

Conditional

在开发环境下,我们经常需要编写一些调试方法,而在打包时又需要去除这些代码。挨个删除显然是不现实的,此时就需要用到[Conditional]特性。它需要在参数中传递一个字符串,编译器会根据这个字符串寻找同名的宏。如果这个宏定义了,该特性修饰的方法就会启用,反之则禁用。

#define IsShowMessage

// ...
[Conditional("IsShowMessage")]
public static void Test2()
{
	Console.WriteLine("调试信息。。。。");
}
// ...

因此在调试过程中,先用[Conditional]特性标记调试方法,调试完毕将#define IsShowMessage注释即可一键禁用标记过的调试方法。

通过上面的几个示例,我们再来理解特性的定义:

  • 将应用了特性的程序结构叫做目标
  • 设计用来获取和使用元数据的程序(对象浏览器)叫做特性的消费者
  • NET预定了很多特性,我们也可以声明自定义特性

重要的一点就是Attribute就是一个类,Attribute类是在编译的时候被实例化的,而不是像通常的类那样在运行时候才实例化。

我们对编写的类、方法、属性,方法的参数,方法的返回值等通过特性进行标记,编译器就会根据特性产生元数据,再将这些元数据放入程序集中。消费者就可以获取到这些元数据,并进行使用。

Attribute类

除了.NET提供的那些Attribute派生类之外,我们可以自定义我们自己的Attribute,所有自定义的Attribute必须从Attribute类派生。现在我们来看一下Attribute 类的细节:

三个静态方法:

  • static Attribute GetCustomAttribute():这个方法有8种重载的版本,它被用来取出施加在类成员上指定类型的Attribute。
  • static Attribute[] GetCustomAttributes(): 这个方法有16种重载版本,用来取出施加在类成员上指定类型的Attribute数组。
  • static bool IsDefined():由八种重载版本,看是否指定类型的定制attribute被施加到类的成员上面。

实例方法:

  • bool IsDefaultAttribute(): 如果Attribute的值是默认的值,那么返回true。
  • bool Match():表明这个Attribute实例是否等于一个指定的对象。

公共属性:

  • TypeId: 得到一个唯一的标识,这个标识被用来区分同一个Attribute的不同实例。

自定义特性

首先,特性是一个类。在自定义特性时,我们自定义的特性类名中必须包含Attribute,同时继承(直接继承或者间接继承)Attribute类。然后需要在该类上通过AttributeUsage特性指明自定义特性的应用范围。比如我们定义一个TestAttribute特性,继承自Attribute类,且要求定义的类只能标记到其他类上面。

   [AttributeUsage(AttributeTargets.Class)]
    public class TestAttribute : Attribute
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public string Say { get; set; }
        public TestAttribute(string name,int age,string say)
        {
            this.Name = name;
            this.Age = age;
            this.Say = say;
        }
    }

AttributeTargets.Class表示,自定义特性TestAttribute只能标记到类上面。然后我们在定义一个类UseTest,将自定义特性标记到该类上,使用自定义特性时不需要加Attribute后缀。通过反射可以获取到指定的特性:

 [Test("小明",30," say hello")]
    public  class UseTest
    {
        public static void AttributeTestMain()
        {
            //获取UseTest类型
            var type = typeof(UseTest);
            //判断该类型是否定义了TestAttrubte特性
            if (type.IsDefined(typeof(TestAttribute), false))
            {
                //通过反射获取自定义特性属性
                var customAttributes = type.GetCustomAttributes(false);
                if (customAttributes.Length > 0)
                {
                    var classinfo = Array.Find(customAttributes, x => x is TestAttribute) as TestAttribute;
                    Console.WriteLine($"名字:{classinfo?.Name}\n年龄:{classinfo.Age}\n说:{classinfo.Say}");
                }
            }
        }

    }

在调用UseTest类中的静态方法AttributeTestMain()后,输出信息为:

非常有意思的是,AttributeUsage本身也是一个Attribute,这是专门施加在Attribute类的Attribute. AttributeUsage自然也是从Attribute派生。AttributeUsage除了继承Attribute 的方法和属性之外,还定义了以下三个属性:

  • AllowMultiple: 读取或者设置这个属性,表示是否可以对一个程序元素施加多个Attribute 。
  • Inherited:读取或者设置这个属性,表示是否施加的Attribute 可以被派生类继承或者重载。
  • ValidOn: 读取或者设置这个属性,指明Attribute 可以被施加的元素的类型。

AttributeUsage的使用例子

using System; 
namespace AttTargsCS 
{ 

   // 该Attribute只对类有效. 
   [AttributeUsage(AttributeTargets.Class)]
   public class ClassTargetAttribute : Attribute 
   { 
    } 


   // 该Attribute只对方法有效. 
   [AttributeUsage(AttributeTargets.Method)]
   public class MethodTargetAttribute : Attribute 
   { 
    } 


   // 该Attribute只对构造器有效。
   [AttributeUsage(AttributeTargets.Constructor)]
   public class ConstructorTargetAttribute : Attribute 
   { 
    } 


   // 该Attribute只对字段有效. 
   [AttributeUsage(AttributeTargets.Field)]
   public class FieldTargetAttribute : Attribute
   {
   } 

   
  // 该Attribute对类或者方法有效(组合). 
  [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
   public class ClassMethodTargetAttribute : Attribute
   {
    } 


   // 该Attribute对所有的元素有效.
   [AttributeUsage(AttributeTargets.All)]
   public class AllTargetsAttribute : Attribute 
  { 
   } 

   //上面定义的Attribute施加到程序元素上的用法
   [ClassTarget]  //施加到类
   [ClassMethodTarget]//施加到类
   [AllTargets] //施加到类
   public class TestClassAttribute
   { 
      [ConstructorTarget] //施加到构造器
      [AllTargets] //施加到构造器
      TestClassAttribute()
      { 
       } 

      [MethodTarget] //施加到方法
      [ClassMethodTarget] //施加到方法
      [AllTargets] //施加到方法
      public void Method1()
      {
      }
     
      [FieldTarget] //施加到字段
      [AllTargets] //施加到字段
      public int myInt; 

      static void Main(string[] args)
      { 
      } 
   }
} 

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

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

相关文章

【批处理DOS-CMD命令-汇总和小结】上网和通信相关命令-查看路由表,查看网卡GUID UUID(route、getmac)

一、查看、编辑路由表(route) 首先我们看看route命令的帮助信息,可以发现这个命令其实就是用来查看路由表、以及添加(或编辑、删除)路由项目的。 路由项目是指操作系统对数据包的导向规则,往往包括目标IP…

《统计学习方法》——条件随机场#习题解答#

引言 这是统计学习方法第十一章条件随机场的阅读笔记,包含所有公式的详细推导。 条件随机场(conditional random field,CRF)是给定一组输入随机变量条件下另一组输出随机变量的条件概率分布模型,其特点是假设输出随机变量构成马尔可夫随机场。 建议先阅…

【计算机网络】为什么是TCP四次挥手,可以变成三次吗?

【计算机网络】为什么是TCP四次挥手,可以变成三次吗? 文章目录 【计算机网络】为什么是TCP四次挥手,可以变成三次吗?引言TCP 四次挥手为什么 TCP 挥手需要四次呢?粗暴关闭 vs 优雅关闭 什么情况会出现三次挥手&#xf…

MySQL—SQL优化详解(下)

♥️作者:小刘在C站 ♥️个人主页: 小刘主页 ♥️努力不一定有回报,但一定会有收获加油!一起努力,共赴美好人生! ♥️学习两年总结出的运维经验,以及思科模拟器全套网络实验教程。专栏&#xf…

FFmpeg 内存模型分析

标题 1. 内存模型图2. 分析流程3.追溯本源————源码分析3.1 AVPacket队列 什么时候生成的? 4 .AVPacket和AVFrame相关操作API5. av_read_frame源码分析 1. 内存模型图 2. 分析流程 我们解复用后,媒体流数据就会被分离开来,分别生成对应AVPacketList,然后通过av_…

BART论文解读

1 概述 全称:Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension。BART来源于Bidirectional and Auto-Regressive Transformers发表时间: 2019.10.29团队:Facebook AI Paper地址​arxiv.o…

chatgpt赋能python:Python怎么求解方程

Python怎么求解方程 在数学中,求解方程是一种基本的技能。Python作为一种广泛应用于科学计算和数据分析领域的编程语言,可以帮助我们求解各种类型的方程。Python提供了多个库和函数,使得求解方程在Python中变得非常轻松。 一元方程求解 一…

Android Framework分析SystemServer进程

SystemServer进程是Android系统的核心进程,运行在Android系统启动后,负责管理和加载系统服务。本文将介绍SystemServer进程的详细结构和工作原理,并使用代码注释的方式阐述其关键部分代码。 结构: SystemServer进程的核心是Syste…

SSH基本概念,带你了解SSH

1、SSH基本概念 SSH(Secure Shell)是一种网络协议,用于在不安全的网络中安全地传输数据。它是一种加密协议,可以保护数据在传输过程中不被窃取、篡改或伪造。SSH协议最初是由芬兰的Tatu Ylonen开发的,现在已经成为了一…

Hadoop集群之模板虚拟机的安装

Hadoop集群之模板虚拟机的安装 文章目录 Hadoop集群之模板虚拟机的安装0. 写在前面1. CentOS的安装1.1 配置电脑1.1.1 进入VMware1.1.2 自定义新的虚拟机1.1.3 解决虚拟机的兼容性1.1.4 选择当前虚拟机的操作系统1.1.5 选择虚拟机将来需要安装的系统1.1.6 电脑的具体配置1.1.7 …

KUKA机器人通过示教器进行关机冷启动的具体方法演示

KUKA机器人通过示教器进行关机冷启动的具体方法演示 如下图所示,首先需要登录管理员权限,默认密码:KUKA,然后点击左上角的机器人图标进行菜单选项,找到并点击“关机”选项, 如下图所示,找到并点击“重新启动控制系统PC”, 如下图所示,此时系统提示:确实要重新启动…

chatgpt赋能python:Python生成序列的方法详解

Python生成序列的方法详解 在Python编程中,序列(Sequence)是常用的数据类型之一。序列是有序的,可以通过下标访问其中的元素。Python中有多种方法可以生成序列,下面将对常用的几种方法进行详细介绍。 利用range函数生…

2023-06-16 Android Studio 使用CMakeList编译JNI ,最简单的demo源码

一、代码结构图,代码路径https://download.csdn.net/download/qq_37858386/87913001 二、cmakedemo\app\build.gradle 加下面的代码 externalNativeBuild {cmake {cppFlags "-frtti -fexceptions"}}externalNativeBuild {cmake {path src/main/jni/CMakeL…

国内大模型研究

自从chatgpt发布以来,国内大模型发展非常迅速。我对这项目技术也保持了非常多的持续关注,我一直认识,chatGPT以及其他GPT会给社会带来更大的变革。经过专业训练的大模型可以替代部分客服,部分程序员,部分美工&#xff…

Vue全家桶实战 从零独立开发企业级电商系统(免费升级Vue3.0)

Vue全家桶高仿小米商城–项目简介 文章目录 Vue全家桶高仿小米商城--项目简介电商项目选型--小米商城的页面流程:业务开发流程:项目内容:商城组件部分:课程所包含的知识图谱:章节介绍: 商城的界面展示&…

基于web漏洞扫描及分析系统设计_kaic

基于web漏洞扫描及分析系统设计 摘 要 随着信息技术的发展和网络应用在我国的普及,针对我国境内信息系统的恶意网络攻击也越来越多,并且随着黑客攻击技术的不断地更新,网络犯罪行为变得越来越难以应对,用户日常访问的网站是否安全…

【八大排序(六)】快排终极篇-快速排序非递归版

💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:八大排序专栏⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习排序知识   🔝🔝 快排非递归版 1. 前情回顾2. 快排非递归基…

A100 GPU服务器安装CUDNN教程

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

从Window中先多瞥几眼

JavaFx17官方文档中有如下的描述: Window类是一个顶层窗口类,在其中可以承载场景,并与用户交互。窗口可以是Stage、PopupWindow或其他类似的顶层窗口。 JavaFX Stage类是顶级的JavaFX容器。初级阶段由平台搭建。其他Stage对象可以由应用程序构造。 许多Stage属性是只读的…

chatgpt赋能python:Python入门:如何添加Seaborn库

Python入门:如何添加Seaborn库 Python是一种易于学习的、功能强大的编程语言,在数据分析和科学计算方面尤其闻名。Seaborn是一个建立在Matplotlib之上的Python可视化库,它提供了一组简单易用的界面,用于绘制优美的统计图形——包…