C#入门(13):特性Attribute

news2024/7/6 9:35:27

C# 特性(Attributes)是用于在运行时为程序元素(如类、方法、属性等)添加声明性信息的一种方式。这些信息可以在程序运行时通过反射(Reflection)访问。特性可以用来控制程序行为、添加元数据或者影响程序的运行时行为。

.Net 框架提供了两种类型的特性:预定义特性和自定义特性。
在这里插入图片描述
用法如下:

#define DEBUG_PRINT

using System;
using System.Diagnostics;

class Test
{
    // 如果定义的 DEBUG_PRINT ,该函数可以执行;没有定义DEBUG_PRINT,该函数将无法执行
    [Conditional("DEBUG_PRINT")]
    static void function1()
    {
        Console.WriteLine("DEBUG_PRINT In Function 1.");
    }

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

    public static void NewMethod()
    {
        Console.WriteLine("It is the new method");
    }

    public static void Main()
    {
        Console.WriteLine("Main");

        //OldMethod();  提示,Don't use OldMethod, use NewMethod instead

        function1();
    }
}

Conditional

Conditional类似于条件编译,在上面的程序中当预定义DEBUG_PRINT,那么运行时就会调用function1,预定义放到了代码文件的最上面:

#define DEBUG_PRINT

Obsolete

Obsolete表示舍弃,可用于警告提示。

自定义属性

MyCustomAttribute.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Attribute02
{
    [AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct|
        System.AttributeTargets.Method)]
    internal class MyCustomAttribute : System.Attribute
    {
        private string description;
        private string returnType;

        // 在构造函数中指定属性信息
        public MyCustomAttribute(string desc, string returnType)
        {
            this.description = desc;
            this.returnType = returnType;
        }

        public string GetDescription()
        {
            return this.description;
        }

        public string GetReturnType()
        {
            return this.returnType;
        }
    }
}

使用MyCustomAttribute修饰类MyClass和它的成员方法GetSum

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Attribute02
{
    [MyCustomAttribute("This is a custom description", "Class No return")]
    internal class MyClass
    {
        [MyCustomAttribute("This is a custom description", "Method int return")]
        public int GetSum(int x, int y)
        {
            return x + y;
        }
    }
}

Main测试

namespace Attribute02
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("测试自定义属性");

            // 反射出类的属性信息
            Type type = typeof(MyClass);
            object[] attributes = type.GetCustomAttributes(typeof(MyCustomAttribute), true);

            foreach (MyCustomAttribute attr in attributes)
            {
                Console.WriteLine(attr.GetDescription());
                Console.WriteLine(attr.GetReturnType());
            }

            // 反射出方法的属性信息
            var method = typeof(MyClass).GetMethod("GetSum");
            var attributesMethon = method.GetCustomAttributes(typeof(MyCustomAttribute), false);

            if (attributesMethon.Length > 0)
            {
                var myAttribute = (MyCustomAttribute)attributesMethon[0];
                Console.WriteLine(myAttribute.GetDescription());
                Console.WriteLine(myAttribute.GetReturnType());
            }
        }
    }
}

运行结果如下:
测试自定义属性
This is a custom description
Class No return
This is a custom description
Method int return

自定义特性应用多个属性

在C#中,AttributeUsage 属性用来定义一个自定义属性可以应用到的程序元素,以及该属性是否可以多次应用和是否可以被继承。
validOn它是枚举器 AttributeTargets 的值的组合。默认值是 AttributeTargets.All。用以指定特性可以应用到哪些程序元素(如类、结构、方法等)上。

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

AllowMultiple 参数是一个布尔值,指示是否可以对单一程序元素应用多个此类特性实例。
Inherited 参数也是一个布尔值,指示特性是否可以被派生类继承。
例如

namespace Attribute03
{
    // 定义一个自定义特性,可以应用于类和结构,可以被继承,并且允许多次应用
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = true)]
    public class MyCustomAttribute : Attribute
    {
        public string Name { get; set; }

        public MyCustomAttribute(string name)
        {
            Name = name;
        }
    }
}

使用MyCustomAttribute修饰ExampleClass

namespace Attribute03
{
    // 应用自定义特性到一个类多次
    [MyCustomAttribute("ExampleClass")]
    [MyCustomAttribute("AnotherNameForTheSameClass")]
    public class ExampleClass
    {
        // 类的实现内容
    }
}

Main测试

namespace Attribute03
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Attribute03");

            // 通过反射获取特性信息
            var attributes = typeof(ExampleClass).GetCustomAttributes(typeof(MyCustomAttribute), true);
            foreach (MyCustomAttribute attr in attributes)
            {
                Console.WriteLine($"Class {typeof(ExampleClass).Name} has the custom attribute with name: {attr.Name}");
            }
        }
    }
}

其它用法

C# 特性Attribute除了用于添加元数据和通过反射检索信息之外,它们还可用于以下目的:

  1. 控制程序行为

    • 编译器指令:特性可以用来给编译器提供指令,如 [Obsolete] 用于标记过时的代码元素。
    • 条件编译:特性可用于条件编译,例如 [Conditional("DEBUG")] 可以使方法仅在 DEBUG 模式下编译和执行。
  2. 数据验证

    • 在数据模型中,特性经常用于验证数据。例如,在实体框架(Entity Framework)或数据注释(Data Annotations)中,你可以使用 [Required], [StringLength] 等特性来定义数据验证规则。
  3. 序列化和反序列化控制

    • 在数据序列化过程中,特性用于控制如何将对象转换为 XML 或 JSON 等格式。例如,[Serializable][DataContract][DataMember]
  4. 拦截器和动态代理

    • 在面向切面编程(AOP)中,特性用于定义方法拦截器。这在动态代理创建时特别有用,例如在 .NET Core 中的依赖注入(DI)。
  5. 声明性安全

    • 特性可用于定义安全要求,如 [PrincipalPermission] 用于声明方法执行所需的安全上下文。
  6. 编写插件和扩展

    • 在插件架构中,特性可用于标识插件类或方法,便于动态加载和识别。
  7. 单元测试框架

    • 在单元测试中,特性用于标记测试方法和测试类(例如 [TestMethod][TestClass]),以及进行测试设置和清理(如 [TestInitialize][TestCleanup])。
  8. 依赖注入配置

    • 在依赖注入(DI)中,特性可以用于标记构造函数、属性或方法,以指导 DI 容器如何进行注入。
  9. 框架和库集成

    • 许多框架和库使用特性来集成与特定框架或库的功能,如 ASP.NET Core 中的路由、授权和过滤器特性(如 [Route], [Authorize], [ActionFilter] 等)。

通过这些用途,C# 特性成为了一种强大的机制,可以在不改变代码本身逻辑的情况下丰富和扩展代码的功能。

代码如下:

1. 编译器指令([Obsolete] 特性)

public class MyClass
{
    [Obsolete("Use NewMethod instead", false)]  // 标记为过时
    public void OldMethod()
    {
        Console.WriteLine("This is the old method.");
    }

    public void NewMethod()
    {
        Console.WriteLine("This is the new method.");
    }
}

2. 数据验证(使用数据注释)

using System.ComponentModel.DataAnnotations;

public class User
{
    [Required]
    public string Name { get; set; }

    [StringLength(10, ErrorMessage = "ID cannot be longer than 10 characters.")]
    public string ID { get; set; }
}

3. 序列化和反序列化控制([Serializable][DataMember] 特性)

using System.Runtime.Serialization;

[Serializable]
public class Person
{
    public string Name { get; set; }

    [DataMember]
    public int Age { get; set; }
}

4. 面向切面编程(AOP)中的方法拦截器

public class LoggingAttribute : Attribute
{
    // 这里只是示例,实际的拦截实现需要结合拦截器框架使用
    public void BeforeCall() => Console.WriteLine("Before method call");
    public void AfterCall() => Console.WriteLine("After method call");
}

public class MyClass
{
    [Logging]
    public void MyMethod()
    {
        Console.WriteLine("Executing the method.");
    }
}

5. 声明性安全

using System.Security.Permissions;

public class SecureClass
{
    [PrincipalPermission(SecurityAction.Demand, Role = "Administrator")]
    public void SecureMethod()
    {
        Console.WriteLine("This method requires the Administrator role.");
    }
}

6. 插件和扩展标识

public class PluginAttribute : Attribute
{
    public string Name { get; set; }
}

[Plugin(Name = "MyPlugin")]
public class MyPlugin
{
    // 插件的实现
}

7. 单元测试

using Microsoft.VisualStudio.TestTools.UnitTesting;

[TestClass]
public class MyTestClass
{
    [TestMethod]
    public void MyTestMethod()
    {
        // 测试代码
    }
}

8. 依赖注入配置

public class MyService
{
    [Inject]
    public IDependency MyDependency { get; set; }
    // 假设 Inject 是一个标记依赖注入的特性
}

9. 框架和库集成

using Microsoft.AspNetCore.Mvc;

public class MyController : Controller
{
    [Route("api/myroute")]
    public IActionResult MyAction()
    {
        return Ok();
    }
}

以上代码示例涵盖了特性在 C# 中的各种不同用途,展示了特性如何被应用于实际编程场景中。

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

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

相关文章

为何公司强调流程员工总是觉得反感?

在企业管理中,流程设计对于提高效率和降低风险至关重要。然而,很多企业在流程设计时常犯一些常见的错误,导致基层员工对流程感到烦扰,甚至产生抵触情绪。本文将通过分析一个企业的报销流程问题,探讨如何优化流程以提高…

mysqlbinlog使用记录

首先要确认mysql启用了binlog功能。一般默认启用。 mysql> select log_bin; ----------- | log_bin | ----------- | 1 | ----------- 然后确认binlog目录 mysql> select log_bin_basename; ---------------------------- | log_bin_basename | -----…

【【VDMA彩条显示实验之四 含C语言代码】】

VDMA彩条显示实验之四 含C语言代码 VTC 手册简介 所有的视频都需要有时序 有时序的地方就需要有 时序控制器 VTC的 主要作用是 产生 视频时序 相对于上一节 在这里 我们会理解的更多 观察 这个 HB 信号 其实这个和上一节的图片差不多 在 行同步信号 前面就是前沿 在 行同步…

【数据结构初阶】单链表SLlist

描述 不同于顺序表,顺序表的数据是存储在一个连续的空间里的 而链表它是链接起来的结构体地址。 所以我们不用像顺序表一样先创建一块空间出来,而是创建一个能存数据节点和节点与下一个节点之间的连接; 所以:“一个能存数据节点…

基于SpringBoot+Redis的前后端分离外卖项目-苍穹外卖(六)

新增菜品 1.1 需求分析与设计1.1.1 产品原型1.1.2 接口设计1.1.3 表设计 2.2 代码开发2.2.1 文件上传实现2.2.2 新增菜品实现 2.3 功能测试 1.1 需求分析与设计 1.1.1 产品原型 后台系统中可以管理菜品信息,通过 新增功能来添加一个新的菜品,在添加菜品…

BUUCTF [BJDCTF2020]just_a_rar 1

BUUCTF:https://buuoj.cn/challenges 题目描述: 来源:https://github.com/BjdsecCA/BJDCTF2020 密文: 下载附件,解压得到一个.rar压缩包。 解题思路: 1、根据压缩包的名字提示我们使用4位纯数字进行破解。使用ARCH…

006 OpenCV腐蚀膨胀

目录 一、环境 二、形态学原理 三、代码演示 一、环境 本文使用环境为: Windows10Python 3.9.17opencv-python 4.8.0.74 二、形态学原理 在图像处理中,腐蚀和膨胀是两种基本的形态学操作,它们可以有效地用于图像的噪声减少、形状分析和…

目标检测 Faster RCNN全面解读复现

Faster RCNN 解读 经过R-CNN和Fast RCNN的积淀,Ross B. Girshick在2016年提出了新的Faster RCNN,在结构上,Faster RCNN已经将特征抽取(feature extraction),proposal提取,bounding box regression(rect refine)&…

红海云签约广州无线电集团,头部国企人力资源数字化转型全面加速

广州无线电集团创立于1995年2月28日,是在1960年(国家第二个五年计划期间)隶属于国家第四机械工业部(后国家电子工业部)的国营第七五〇厂的基础上整体注册而成,其历史可以追溯至1956年在公私合营背景下组建的…

JDY蓝牙注意事项

波特率设置:9600,不接受115200,或者38400. 不同于WiFi测试,jdy蓝牙不接受AT"指令,可以使用“ATVERSION"指令测试 安信可公司的那个蓝牙指令在这里没有用,不知道是不是生产的公司不一样

宽瞬时带宽放大器SKY66051-11、SKY66052-11、SKY66041-11、SKY66317-11(RF)适用于通讯网络

一、2300至2700 MHz宽瞬时带宽高增益线性驱动放大器:SKY66051-11 SKY66051-11是一款具有高增益和高线性度的宽瞬时带宽、完全输入/输出匹配驱动放大器。通过使用外部元件,增益可在30dB至36dB范围内调整。紧凑型33 mm PA专为工作频率为2300至2700 MHz的4…

终结痛点!超级素材中转站,轻松实现素材跨设备使用

华为升级HarmonyOS 3系统后,更新了“中转站”功能。该功能允许各种类型的文件在华为设备间无缝流动,包括但不限于图片、视频和文档等。借助"中转站",你可以毫不费力地将文件从一个华为设备传送到另一个华为设备,避免了电…

服务器IPMI管理操作

简介:智能平台管理界面(IPMI,Intelligent Platform Management Interface)是管理基于 Intel 结构的企业系统中所使用的外围设备采用的一种工业标准,用户可以利用IPMI监视服务器的物理健康特征,如温度、电压、风扇工作状…

分享职业技术培训类型

职业技术培训类型包括:Python技术应用、人工智能应机器学习、大数据分析、机器学习。 一、“Python技术应用工程师” “Python技术应用工程师”职业技术认证是由工业和信息化部教育与考试中心推出一套专业化、科学化、系统化的人才考核标准,涉及在互…

thinkphp8 DB_PREFIX 属性

设计表的时候使用**_user, **就是前缀,DB_PREFIX就是默认把前缀给去掉 在config/database.php prefix,改成你的前缀,数据库的表重命名‘ltf_user’ 代码调用 $user Db::name("user")->select();return json($user);之前是使用…

智慧校园烟火识别及预警解决方案,保障校园消防安全

一、方案背景 校园消防安全一直以来是社会各界备受关注的问题。为了保障师生的人身安全和财产安全,越来越多的学校开始引入AI智能检测技术,通过运用AI智能烟火检测技术,对学校的周界、教室、走廊、公共区域、教学楼、食堂等场所进行安全监测…

redis非关系型数据库(缓存型数据库)——中间件

【重点】redis为什么这么快?(应届) ①redis是纯内存结构,避免磁盘I/O的耗时 ②redis核心模块是一个单进程,减少线程切换和回收线程资源时间 ③redis采用的是I/O的多路复用机制(每一个执行线路可以同时完…

Sqlserver 多行合并为一行

多行合并为一行 表结构 子表结构如下: 父表结构如下: 由图可以看出子表和父表是通过父表ID进行关联的。 我们要实现的效果如下,查询父表数据的同时,增加一列来展示父表下子商品信息。 完整代码如下 select top {0} * from (…

java基础练习缺少项目?看这篇文章就够了(上)!

公众号:全干开发 。 专注分享简洁但高质量的动图技术文章! 项目概述 本教程适合刚学习完java基础语法的同学,涉及if语句、循环语句、类的封装、集合等基础概念,使用大量gif图帮助读者演示代码操作、效果等,是一个非常…

【LeetCode刷题-字符串】--6.N字形变换

6.N字形变换 方法:使用二维矩阵模拟 根据题意,当在矩阵中填写字符时,会向下填写r个字符,然后向右继续填写r - 2个字符,最后回到第一行,因此Z字形变换的周期是t r r - 2 2r - 2,是|/,每个周期…