C#入门(13):特性Attribute

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# 中的各种不同用途,展示了特性如何被应用于实际编程场景中。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构【DS】图的遍历

BFS 要点 需要一个辅助队列visited数组,防止重复访问 复杂度 时间复杂度:访问结点的时间访问所有的边的时间 广度优先生成树 邻接表存储的图的表示方式不唯一,生成树也不唯一 DFS 复杂度 时间复杂度:访问结点的时间访问所有…

【Flink】核心概念:任务槽(Task Slots)

任务槽 每个 worker(TaskManager)都是一个 JVM 进程,可以在单独的线程中执行一个或多个 subtask。为了控制一个 TaskManager 中接受多少个 task,就有了所谓的 task slots(至少一个)。 每个任务槽&#xf…

CICD 持续集成与持续交付——git

git使用 [rootcicd1 ~]# yum install -y git[rootcicd1 ~]# mkdir demo[rootcicd1 ~]# cd demo/ 初始化版本库 [rootcicd1 demo]# git init 查看状态 [rootcicd1 demo]# git status[rootcicd1 demo]# git status -s #简化输出 [rootcicd1 demo]# echo test > README.md[roo…

树,二叉树,二叉树遍历,哈夫曼树(详解+刷题)

👂 后街男孩经典之精选 - 歌单 - 网易云音乐 👂 年轮(电视剧《花千骨》男声版插曲) - 汪苏泷 - 单曲 - 网易云音乐 目录 🌼5.1 -- 树 🌼5.2 -- 二叉树 1,性质 2,存储 3&#x…

【开源】基于Vue.js的智能教学资源库系统

项目编号: S 050 ,文末获取源码。 \color{red}{项目编号:S050,文末获取源码。} 项目编号:S050,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 课程档案模块2.3 课…

CDN是什么,能起到什么作用

随着互联网的快速发展,用户对于快速、稳定、高效的互联网体验的需求日益增长。为了满足这一需求,内容分发网络(CDN)应运而生,并在近年来得到了广泛应用。CDN通过在全球范围内部署大量的服务器和网络节点,实…

【C++】【Opencv】cv::Canny()边缘检测函数详解和示例

Canny边缘检测是一种流行的边缘检测算法,由John F. Canny在1986年开发。它是一种多阶段过程,包括噪声滤波、计算图像强度的梯度、非最大值抑制以及双阈值检测。本文通过函数原型解读和示例对cv::Canny()函数进行详解,以帮助大家理解和使用。 …

[AutoSar]CP autosar 面试题

目录 关键词前言面试官提问答案 关键词 嵌入式、C语言、autosar、面试题 前言 以前面试中的一些常提到的问题,在这里整理一下,希望对要去面试的道友有所帮助。 其中问题的答案后续有时间会再更新整理。 面试官提问 1.Autosar 概述: 解释 …

MyBatis 快速入门

MyBatis 快速入门 前言什么是 MyBatis简介核心特性使用示例配置文件Mapper 接口SQL 映射文件使用 MyBatis 如果大家对以上的导读很懵怎么办!没关系 往下阅读! 1. MyBatis 介绍1.1. 什么是MyBatis1.2. 持久层1.3. 框架1.4. JDBC 弊端1.5.…

【Java】网络编程基础—InetAddress类和URL编程

🌺个人主页:Dawn黎明开始 🎀系列专栏:Java ⭐每日一句:为了那个远方,你要奋不顾身 📢欢迎大家:关注🔍点赞👍评论📝收藏⭐️ 文章目录 一.&#x…

【开源】基于Vue.js的独居老人物资配送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询社区4.2 新增物资4.3 查询物资4.4 查询物资配送4.5 新增物资配送 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的独居老人物资配送系统,包含了社区档案、…

C++模拟实现——红黑树封装set和map

一、红黑树迭代器的实现 基本的框架和实现链表的迭代器思路是一样的,都是对指针进行封装处理,然后实现一些基本的运算符重载,最重要的是operator,需要不递归的实现走中序的规则,这里只实现那最核心的几个基本功能&…

Day35力扣打卡

打卡记录 相邻字符不同的最长路径(树状DP) 链接 若节点也存在父节点的情况下,传入父节点参数,若是遍历到父节点,直接循环里 continue。 class Solution:def longestPath(self, parent: List[int], s: str) -> in…

如何看待人工智能行业发展

随着人工智能技术的飞速发展,这个领域的就业前景也日益广阔。人工智能在各行各业都有广泛的应用,包括医疗、金融、制造业、教育等。因此,对于想要追求高薪、高技能职业的人来说,学习人工智能是一个非常有前景的选择。 首先&#x…

【Python进阶】近200页md文档14大体系知识点,第4篇:linux命令和vim使用

本文从14大模块展示了python高级用的应用。分别有Linux命令,多任务编程、网络编程、Http协议和静态Web编程、htmlcss、JavaScript、jQuery、MySql数据库的各种用法、python的闭包和装饰器、mini-web框架、正则表达式等相关文章的详细讲述。 全套Python进阶笔记地址…

阿里云ECS11月销量王 99元/年

这一波好像真没得说,老用户居然都有份,买来练习、测试冒似已经够了! 阿里云ECS11月销量王 99元/年 2核2G 3M固定带宽不限流量,新老同享,新购、续费同价,开发必备! 活动规则 云服务器ECS 云创季…

读像火箭科学家一样思考笔记03_第一性原理(上)

1. 思维的两种障碍 1.1. 为什么知识会成为一种缺陷而非一种美德 1.1.1. 知识是一种美德 1.1.2. 知识同样的特质也会把它变成一种缺点 1.1.3. 知识确实是个好东西,但知识的作用应该是给人们提供信息,而不是起约束作用 1.1.4. 知识应该启发智慧&#…

程序员告诉你:人工智能是什么?

随着科技的快速发展,人工智能这个词汇已经逐渐融入了我们的日常生活。然而,对于大多数人来说,人工智能仍然是一个相对模糊的概念。 首先,让我们从人工智能的定义开始。人工智能是一种模拟人类智能的技术,它涵盖了多个领…

【Flink】系统架构

DataStream API 将你的应用构建为一个 job graph,并附加到 StreamExecutionEnvironment 。当调用 env.execute() 时此 graph 就被打包并发送到 JobManager 上,后者对作业并行处理并将其子任务分发给 Task Manager 来执行。每个作业的并行子任务将在 task…

微服务调用链路追踪

概述 本文介绍微服务调用链路追踪,涉及技术有:sleuth和zipkin。sleuth负责追踪调用链路数据,zipkin负责调用链路数据可视化展现。 本文的操作是在 服务网关实践 的基础上进行。 环境说明 jdk1.8 maven3.6.3 mysql8 spring cloud2021.0.8 …