C#特性和反射

news2025/3/18 8:26:22

1。特性概念理解?

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

特性是【运行时】给各种元素添加【声明性标签】。语法:[某个特性]。 声明性标签:官方称为元数据,即:metadata
元数据:保存在程序集中有关程序及其类型的数据。元数据主要用来描述C#中各种对象(类,方法,构造函数,属性等)。

// 特性主要用来给各种对象添加元数据。反射主要用来拿各种对象的元数据。

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

问:属性和特性啥关系?没关系。两个概念。属性Property,是类的成员。特性Attribute,用来描述类,方法等对象的元数据。

常用的特性:

AttributeUsage,Conditional,Obsolete,Category,Description,Browsable,DefaultValue,Serializable,在学习自定义控件时会用到部分特性。
// 多个特性无顺序,多个中括号设置
// Description特性用来给属性添加描述信息(注释,解释)
// Category特性用来给属性分类,默认分类放到“杂项”
// Browsable特性用来控制属性能否在属性窗口中出现

三种预定义特性分类:

• AttributeUsage预定义特性

主要让开发者在自定义特性时,控制自定义特性的应用范围,掌握
预定义特性 AttributeUsage 描述了如何使用一个自定义特性类。它规定了特性可应用到的项目的类型。

规定该特性的语法如下:

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

其中:

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

// AttributeUsage特性,控制定义的特性在哪些对象上使用。 
//即:自定义的特性MyAttribute可以应用到哪些目标上。Usage使用
// 平时自定义的特性最想用到:类上,方法,属性。
// AttributeTargets特性应用的目标。Targets目标
// AllowMultiple = true控制特性是否能在同一个元素上应用多次,
//false只能应用一次,是默认情况,true可能应用多次
[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

如何自定义一个特性?

1。命名建议以Attribute结尾,建议使用大驼峰。
2。必须继承基类Attribute
3。使用AttributeUsage特性来控制自定义的特性的应用范围。

观察:怎么判断对象是一个特性呢?看对象的结尾是否以Attribute结尾,只要以Attribute结尾的基本上是特性。
特性在定义时,建议以Attribute结尾。特性肯定是一个类,必须继承Attribute。Atribute是特性的基类。

2。反射?

反射是指在程序运行中,查看、操作其他程序集或者自身的元数据的各种信息(类、方法,属性、变量、对象等)的行为。C#中的反射(Reflection)是一种强大的功能,允许你在运行时检查和操作程序集、类型和对象的信息,基本上,使用反射可以在代码运行时检查和操作指定的类及其成员。C#反射的原理主要基于元数据(与C#特性相似),即程序集中存储的有关类型、方法等的信息。因为反射可以在程序编译后获得信息,所以它提高了程序的拓展性和灵活性。

反射就是为了拿到各种元素对应的标签。Reflection反射。使用反射时,代码性能低,因为反射使用了装箱和拆箱。

 // 1。反射拿类型
 Type type3 = typeof(Student);

 Student t = new Student();  // 没有使用反射,直接创建实例
 Type type4 = t.GetType();

// 2。通过类型获取字段,属性,方法,
 // 通过反射创建实例
 // Assembly.Load("1.特性")加载程序集,CreateInstance(完整的对象的名称)用加载的程序集在创建一个程序集中的对象的实例
 // 如果加载的程序集在当前项目中的bin/debug中不存在,会加载失败。
  Assembly assembly = Assembly.Load("1.特性"); // 拿程序集
 // 使用反射技术创建程序集中的某个类的实例。装箱的操作
 object t1 = assembly.CreateInstance("_1.特性.Student");  // 类似于Student t = new Student();
 
  //FieldInfo fieldInfo = type3.GetField("_id"); // 获取单个字段
 //fieldInfo.SetValue(t1, 1);  // 给字段设置值   相当于_id=10, 报错:私有的无法访问
 FieldInfo fieldInfo = type3.GetField("myId");
 int myId = (int)fieldInfo.GetValue(t1);  // 获取公开的字段值,使用装箱和拆箱
 Console.WriteLine(myId);

 fieldInfo.SetValue(t1, 20); // 设置字段值
 int myId2 = (int)fieldInfo.GetValue(t1);
 Console.WriteLine(myId2);
  Console.WriteLine("-----------------");
 FieldInfo[] fieldInfos = type3.GetFields();
 foreach (var item in fieldInfos)
 {
     Console.WriteLine(item.GetValue(t1));
 }

 Console.WriteLine("-----------------");
 PropertyInfo propertyInfo1 = type3.GetProperty("Name"); // 拿单个属性
 propertyInfo1.SetValue(t1, "张三"); // 设置属性
 string name = (string)propertyInfo1.GetValue(t1); // 获取属性值
 Console.WriteLine(name);

 Console.WriteLine("-----------------");
 PropertyInfo[] propertyies = type3.GetProperties(); // 拿所有公开属性
 foreach (var item in propertyies)
 {
     if (item.Name == "Id") // 判断属性是不是Id属性
     {
         item.SetValue(t1, 100);
     }
     if (item.Name == "Name")
     {
         item.SetValue(t1, "李四");
     }
     Console.WriteLine(item.GetValue(t1));
 }

 Console.WriteLine("-----------------");
 MethodInfo methodInfo = type3.GetMethod("Method2");  // 拿方法
 methodInfo.Invoke(t1, new object[] { "ABC", 10000 }); // 调用方法


 Type h1 = type3.GetNestedType("Hello"); // 拿到Student类下的Hello类的类型
 object hIns = assembly.CreateInstance(h1.FullName);
 PropertyInfo pInfo = h1.GetProperty("Name");
 object value = pInfo.GetValue(hIns);
 Console.WriteLine(value);

 // 用反射的技术把libs/ClassLibrary1.dll中的Class1应用一下。
 // 直接使用不可能了,原因:此类库没有在当前程序中引用。
 // Class1 class1 = new Class1();  // 代码出错

 // 1。先加载程序集
 string assemblyFile = Path.Combine(Environment.CurrentDirectory, "../../libs/ClassLibrary1.dll");
 Assembly class1Assembly = Assembly.LoadFrom(assemblyFile);
 // 2。创建某个类的实例
 object class1 = class1Assembly.CreateInstance("ClassLibrary1.Class1");
 Type class1Type = class1.GetType();
 // 3。拿成员
 //FieldInfo
 //MethodInfo
 //PropertyInfo
 //MemberInfo其实是FieldInfo,MethodInfo,PropertyInfo等的综合体
 Console.WriteLine("-----------------");
 MemberInfo[] members = class1Type.GetMembers(); // 获取类的所有的成员
 foreach (var item in members)
 {
     // 判断某个成员是否是继承的成员, item.DeclaringType == item.ReflectedType非继承的成员
     if (item.DeclaringType == item.ReflectedType)
     {
         // 判断成员是否是属性
         if (item.MemberType == MemberTypes.Property)
         {
             PropertyInfo p = item as PropertyInfo;
             Console.WriteLine($"属性名:{p.Name},属性值:{p.GetValue(class1)}");
         }
         // 判断成员是否是方法
         if (item.MemberType == MemberTypes.Method)
         {
             
             MethodInfo m = item as MethodInfo;
             // IsSpecialName如果返回true表示是特殊的方法(由属性生成的get/set访问器。
             Console.WriteLine($"方法名:{m.Name},是否是特殊方法:{m.IsSpecialName}");
             if (!m.IsSpecialName)
             {
                 if (m.Name == "Method1")
                 {
                     Console.Write("执行结果:");
                     m.Invoke(class1, null);  // Invoke调用方法
                 }
                 else if (m.Name == "Method2")
                 {
                     object result = m.Invoke(class1, new object[] { "hello world" });
                     Console.WriteLine($"执行结果:{result}");
                 }
             }
         }
     };
 }

结果

在这里插入图片描述

反射重要的API?

t.GetField();// FieldInfo类,拿类的字段
t.GetProperty();// PropertyInfo类,拿类的属性
t.GetMethod(“SayHello”) // MethodInfo类,拿方法的元数据。
t.GetConstructor() // ConstructorInfo类,拿类的构造函数
t.GetEvent();// EventInfo类,拿类的事件
t.GetCustomAttribute();// Attribute类,拿类的特性
typeof() 和 GetType() // 获取类型
Invoke() 和 InvokeMember() // 调用相应的成员
SetValue(),GetValue()// 设置属性,获取属性

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

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

相关文章

mysql5.x和mysql8.x查看和设置隔离级别

MySQL的隔离级别 级别标志值描述读未提交READ-UNCOMMITTED0存在脏读、不可重复读、幻读的问题读已提交READ-COMMITTED1解决脏读的问题,存在不可重复读、幻读的问题可重复读REPEATABLE-READ2mysql 默认级别,解决脏读、不可重复读的问题,存在幻…

3.17学习总结

写了两道题 刚开始用的之前做组合输出的方法&#xff0c;时间超限了&#xff0c;想不出怎么优化&#xff0c;后面看了题解&#xff0c;代码如下 #include <stdio.h> #include <stdlib.h> int n,min2e9; int a[11],b[11]; //搜索 void hly(int s,int x,int y) {//当…

Blender材质 - 层权重

层权重 混合着色器 可以让 面朝向的一面显示一种材质 另一面显示另一种材质 就能实现挺不错的材质效果 移动视角 材质会跟着变化 有点类似虚幻的视差节点BumpOffset

【JavaEE】Spring Boot 日志

目录 一、日志概述二、使用日志2.1 打印日志2.2 日志框架2.2.1 门面 / 外观 模式 2.3 日志级别2.3.1 六大分类2.3.2 使用 2.4 日志级别配置2.5 日志的持久化2.6 日志文件分割2.7 日志文件格式2.8 Slf4j 简单打印日志 一、日志概述 ⽇志主要是为了发现问题, 分析问题, 定位问题…

如何用solidworks画齿轮

齿轮还是很有技术含量的,专业名词太多看不懂, 只会画 (这个东西不能自己想当然画, 齿轮之间不啮合是很有问题的,会积累磨损) 步骤1 打开设计库里的toolbox 选择正齿轮,右键生成零件 需要改的有几个关键的地方,我是只知道内圆外圆所以,对我来说最重要的是标称轴直径 (即正中间…

详解布隆过滤器及其模拟实现

目录 布隆过滤器 引入 概念 工作原理 模拟实现布隆过滤器 哈希函数集 布隆过滤器基本框架 add函数&#xff08;添加到布隆过滤器中&#xff09; contains函数&#xff08;判断是否存在该值&#xff09; 完整代码 布隆过滤器的删除 布隆过滤器的误判率 布隆过滤器的…

element-plus中DatePicker 日期选择器组件的使用

1.选择某一天 代码&#xff1a; <el-date-pickerv-model"invoice_date"type"date"placeholder"请选择日期"style"width: 200px;"clearable /> 运行效果&#xff1a; 问题所在&#xff1a;这个数据的格式不是我们后端需要的那种&…

SvelteKit 最新中文文档教程(4)—— 表单 actions

前言 Svelte&#xff0c;一个语法简洁、入门容易&#xff0c;面向未来的前端框架。 从 Svelte 诞生之初&#xff0c;就备受开发者的喜爱&#xff0c;根据统计&#xff0c;从 2019 年到 2024 年&#xff0c;连续 6 年一直是开发者最感兴趣的前端框架 No.1&#xff1a; Svelte …

力扣hot100二刷——二叉树

第二次刷题不在idea写代码&#xff0c;而是直接在leetcode网站上写&#xff0c;“逼”自己掌握常用的函数。 标志掌握程度解释办法⭐Fully 完全掌握看到题目就有思路&#xff0c;编程也很流利⭐⭐Basically 基本掌握需要稍作思考&#xff0c;或者看到提示方法后能解答⭐⭐⭐Sl…

字符串哈希从入门到精通

一、基本概念 字符串哈希是将任意长度的字符串映射为固定长度的哈希值&#xff08;通常为整数&#xff09;的技术&#xff0c;核心目标是实现O(1)时间的子串快速比较和高效查询。其本质是通过数学运算将字符串转换为唯一性较高的数值&#xff0c;例如&#xff1a; ​​​​​​…

C语言:编程设计猜数游戏

先由计算机想一个数给用户猜&#xff0c;如果猜对了&#xff0c;提示“right&#xff01;”&#xff0c;猜错了&#xff0c;提示“wrong&#xff01;及大小” 思路&#xff1a;用随机函数rand&#xff08;&#xff09;取到计算机想的数 代码&#xff1a; #include <stdio.…

win10 c++ VsCode 配置PCL open3d并显示

win10 c VsCode配置PCL open3d并显示 一、效果图二、配置步骤2.1 安装vscode2.2 pcl-open3d配置2.3 vscode中设置 三、测试代码四、注意事项及后续 一、效果图 二、配置步骤 2.1 安装vscode vscode下载链接 下载中文插件、c相关插件 2.2 pcl-open3d配置 1&#xff09;下载…

Vala 开发环境搭建

介绍 Vala 是一种使用现代高级抽象的编程语言&#xff0c;与用 C 语言编写的应用程序和库相比&#xff0c;没有施加额外的运行时要求&#xff0c;也不需要使用不同的 ABI。 Vala 使用 GObject 类型系统&#xff0c;并具有额外的代码生成例程&#xff0c;使面向 GNOME 堆栈变得简…

【网页】自制流光卡片

概述 小红书有个博主自己搞的笔记排版工具叫“流光卡片”&#xff0c;类似的还有个Markdown排版工具叫MD2Card。 我这个版本类似&#xff0c;但是自己写的东西&#xff0c;控制性更好。 初期就写了个静态页面&#xff0c;后期结合Godot快速生成&#xff0c;并可能结合JS库&a…

CSP-J/S冲奖第18天:真题解析

解题步骤 读取输入&#xff1a;首先读取整数n&#xff0c;然后读取n个正整数并存储在一个数组或容器中。 排序数组&#xff1a;对数组进行排序&#xff0c;以便后续使用双指针法高效查找。 遍历数组&#xff1a;对于每个数target&#xff0c;检查是否存在另外两个不同的数a和…

【linux】虚拟机执行sudo yum isntall perl报错 could not retrieve mirrorlist htt:

项目场景&#xff1a; 提示&#xff1a;虚拟机安装拓展包&#xff0c;sudo yum install perl Virtualbox 在不安装增强功能扩展的情况下, 无法自适应分辨率和共享剪切板等操作 问题描述 原因分析&#xff1a; 提示&#xff1a;这里填写问题的分析&#xff1a; 出现这个错误是因…

旅游类小程序界面设计

产品概述 艾啦游是一款互联网旅游类小程序&#xff0c;致力于国内精品旅游&#xff0c;以及拥有自由行、专属热榜单、出行攻略等诸多功能&#xff0c;汇聚了许多国内的人气景点&#xff0c;与诸多城市的酒店也保持合作&#xff0c;打造一体式旅行服务&#xff0c;更有不断上新…

DQN 玩 2048 实战|第三期!优化网络,使用GPU、Env奖励优化

视频讲解&#xff1a; DQN 玩 2048 实战&#xff5c;第三期&#xff01;优化网络&#xff0c;使用GPU、Env奖励优化 1. 仅考虑局部合并奖励&#xff1a;目前的奖励只设置为合并方块时获得的分数&#xff0c;只关注了每一步的即时合并收益&#xff0c;而没有对最终达成 2048 这个…

【python】http post 在body中传递json数据 以发送

http post 在body中传递json数据 以发送&#xff0c;json的格式非常重要这里要传递json对象&#xff0c;而不是一个json字符串 传递post一个 JSON 字符串 是ok的 是的&#xff0c; {"rsource_rhythm_action_list": {"name": "AI_\\u6708\\u4eae\\u…

[贪心算法]-最大数(lambda 表达式的补充)

1.解析 我们一般使用的排序比较大小都是 a>b 那么a在b的前面 ab 无所谓 a<b a在b的后面 本题的排序则是 ab>ba 那么a在b的前面 abba 无所谓 ab<ba a在b的后面 2.代码 class Solution { public:string largestNumber(vector<int>& nums) {//1.先把所有…