(十二)反射与特性 -反射与预定义特性(1)

news2024/11/25 2:52:43

一、反射

1、什么是反射

  • 了解反射之前,要先了解一下元数据。元数据指保存在程序集中的一些有关程序及其类型的数据,包括类、结构、委托、接口和枚举等)的成员和成员的信息。

  • 程序在运行时,可以查看程序集以及其本身的元数据,是反射。

  • 通过反射,可以在运行时获取程序或程序集中的所有类型的元数据。

  • 反射指程序可以访问、检测和修改它本身状态或行为的一种能力。(来源:菜鸟教程)

  • 反射的命名空间是System.Reflection。

具体内容:

.NET 中的反射

2、反射的优缺点

首先在编译中分为动态编译和静态编译,静态编译是在编译中确定类型,绑定对象,而动态编译是在运行中确定类型,绑定对象
反射的优点就是可以动态创建对象、绑定对象,提高了程序的灵活性和扩展性,但反射是一种解释操作,在性能上不如静态编译快

3、 反射(Reflection)的用途

反射(Reflection)有下列用途:

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

4、Type 类

通过反射类的Type,来获取有关构造函数、方法、字段、属性和事件的信息。

Type 是抽象类。在运行时,CLR 创建从 Type(RuntimeType)派生的类的实例,Type 包含了类型信息。当访问这些实例时,CLR 不会返回派生类的引用而是返回 Type 基类的引用

如声明了一个 MyClass 类型,不管创建了多少个 MyClass 类型的实例,就只有一个 Type 对象表示它。即每一个类型对应一个 Type 类型的对象。

表-System.Type 类的部分成员

成员成员类型描述
Name属性返回类型的名字
Namespace属性返回包含类型声明的命名空间
Assembly属性返回声明类型的程序集。如果类型是泛型的,返回定义这个类型的程序集
GetFields方法返回类型的字段列表
GetProperties方法返回类型的属性列表
GetMethods方法返回类型的方法列表

1)获取 Type 对象

通过 object 对象 来获取 Type 对象。

Type t = myInstance.GetType():

示例:

class BaseClass
    {
        public int BaseField = 0;
    }

    class DerivedClass: BaseClass
    {
        public int DerivedField = 0;
    }

    class Program
    {
        static void Main(string[] args)
        {
            var bc = new BaseClass();
            var dc = new DerivedClass();

            BaseClass[] bca = new BaseClass[] { bc, dc };

            foreach(var v in bca)
            {
                Type t = v.GetType();
                Console.WriteLine($"Object type :{ t.Name }");

                FieldInfo[] fi = t.GetFields();
                foreach (var f in fi)
                    Console.WriteLine($"     Field :{ f.Name }");

                Console.WriteLine();
            }

            //Arry 枚举器的Type 类型
            int[] arr = { 10, 11, 12, 13 };
            var arrEnumerator = arr.GetEnumerator();
            Type ArrEnumeratorType = arrEnumerator.GetType();
           var arrEnumeratorProperties = ArrEnumeratorType.GetProperties();

            Console.WriteLine($"Object type :{ ArrEnumeratorType.Name }");

            foreach (var item in arrEnumeratorProperties)
                Console.WriteLine($"   Properties:{ item.Name }");

            Console.ReadKey();
        }
    }

输出结果:

Object type :BaseClass
     Field :BaseField

Object type :DerivedClass
     Field :DerivedField
     Field :BaseField

Object type :SZArrayEnumerator
   Properties:Current

2)使用 typeof 运算符来获取 Type 对象。

    class BaseClass
    {
        public int BaseField = 0;
    }

    class DerivedClass: BaseClass
    {
        public int DerivedField = 0;
    }

    class Program
    {
        static void Main(string[] args)
        {
            Type tbc = typeof(DerivedClass);
            Console.WriteLine($"Object type :{ tbc.Name}");

            FieldInfo[] fi = tbc.GetFields();
            foreach (var f in fi)
                Console.WriteLine($"      Field : { f.Name }");

            Console.ReadKey();
        }
    }

输出结果:

Object type :DerivedClass
Field : DerivedField
Field : BaseField

二、特性

1、什么是特性

特性是一种允许我们向程序的程序集添加元数据的语言结构。它是用于保存程序结构信息的特殊类型的

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

关于图中的特性:

  • 在源码中将特性应用于程序结构。
  • 编译器获取源代码并且从特性产生元数据,然后把元数据放到程序集中。
  • 消费者程序可以获取特性的元数据以及程序中其他组件的元数据,注意,编译器同时产生和消费特性。

请添加图片描述

2、应用特性

特性的目的是告诉编译器把程序结构的某组元数据嵌入程序集。

[Serializable]
public class MyClass
{...}

[MyAttribute("Simple class","Version 3.57")]//带有参数的特性
public class MyOtherClass
{...}

3、预定义的保留特性

1)Obsolete 特性

可以使用 Obsolete 特性将程序结构标注为“过时”,以显示有用的警告消息。

class Program
{
[Obsolete("Use method SuperPrintOut")]//将特性应用到方法
static void PrintOut(string str)
{
Console.WriteLine(str);
}
static void Main(string[] args)
{
PrintOut("Start of Main");//调用 Obsolete 方法
}
}

在 VS 底部栏,错误列表里,显示警告信息:

严重性 代码 说明 项目 文件 行
警告 CS0618 “Program.PrintOut(string)”已过时:“Use method SuperPrintOut”…

如将 Obsolete 特性改为:

[Obsolete("Use method SuperPrintOut",true)]

在 VS 底部栏,错误列表里,显示错误信息:

严重性 代码 说明 项目 文件 行
错误 CS0619 “Program.PrintOut(string)”已过时:“Use method SuperPrintOut”…

2)Conditional 特性

Conditional 特性允许我们包括或排斥特定方法的所有调用。

在方法上使用 Conditional 特性的规则:

  • 该方法必须是类型或结构体的方法。
  • 该方法必须为 void 类型。
  • 该方法不能被声明 overrride,但可以标记为 virtual。
  • 该方法不能是接口方法的实现。
#define DoTrace
using System;
//....
    class Program
    {
        [Conditional("DoTrace")]
        static void TraceMessage(string str)
        {
            Console.WriteLine(str);
        }

        static void Main(string[] args)
        {
            TraceMessage("Start of Main");
            Console.WriteLine("Doing work in Main");
            TraceMessage("End of Main");
            Console.ReadKey();
        }
    }

若定义了编译符号#define DoTrace,输出结果:

Start of Main
Doing work in Main
End of Main

若没有定义编译符号#define DoTrace,输出结果:

Doing work in Main

3)调用者信息特性

利用调用者信息特性可以访问文件路径、代码行数、调用成员的名称等源代码信息。

  • 这3个特性名称为 CallerFilePath、CallerLineNumber 和 CallerMemberName。
  • 这些特性只能用于方法中的可选参数。
    class Program
    {
       public static void MyTrace(string message,
           [CallerFilePath] string fileName = "",
           [CallerLineNumber] int lineNumber = 0,
           [CallerMemberName] string callingMember=""
           )
        {
            Console.WriteLine($"File:   { fileName }");
            Console.WriteLine($"Line:   { lineNumber }");
            Console.WriteLine($"Called From:   { callingMember }");
            Console.WriteLine($"Message:   { message }");
        }

        static void Main(string[] args)
        {
            MyTrace("Simple message");
            Console.ReadKey();
        }
    }

输出结果:

File: C:\Users\用户名\documents\visual studio 2015\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs
Line: 35
Called From: Main
Message: Simple message

4)DebuggerStepThrough 特性

在单步调试代码时,可以通过 DebuggerStepThrough 特性不让调试器进入某些方法里进行调试,而是执行该方法后,直接继续调试下一行代码。

DebuggerStepThrough 特性:

  • 该特性位于 System.Diagnostics 命名空间。
  • 该特性可用于类、结构、构造函数、方法或访问器。
    class Program
    {
        int x = 1;
        int X
        {
            get { return x; }
            [DebuggerStepThrough] //不进入 set 访问器
            set
            {
                x = x * 2;
                x += value;
            }
        }

        public int Y { get; set; }

        [DebuggerStepThrough]//不进入这个方法
        void IncrementFields()
        {
            X++;Y++;
        }

        static void Main(string[] args)
        {
            Program p = new Program();
            p.IncrementFields();
            p.X = 5;
            Console.WriteLine($"X = { p.X }, Y = { p.Y }");
            Console.ReadKey();
        }
    }

调试过程:

请添加图片描述

4、其他预定义特性

特性意义
CLSCompliant声明公开暴露的成员应该被编译器检测其是否符合 CLS。兼容的程序集可以被任何兼容 .NET 的语言使用
Serializable声明结构可以被序列化
NonSerialized声明结构不能被序列化
DLLImport声明是非托管代码实现的
WebMethod声明方法应该被作为 XML Web 服务的一部分暴露
AttributeUsage声明特性能应用于什么类型的程序结构。将这个特性应用到特性声明上

5、多个特性

//多层结构
[Serializable]
[MyAtrribute("Simple class","Version 3.57")]

//逗号分隔
[MyAtrribute("Simple class","Version 3.57"),Serializable]

6、其他类型的目标

目标:字段和属性等程序结构

//字段上的特性
[MyAtrribute("Holds a value","Version 3.2")]
public int MyField;

//方法上的特性
[Obsolete]
[MyAtrribute("Prints out a message.","Version 3.6")]
public void PrintOut()
{
...
}

显示地标注特性:

[method: MyAtrribute("Prints out a message.","Version 3.6")]
[return: MyAtrribute("This value represents...","Version 2.3")]
public long ReturnSetting()
{
...
}

表-特性目标:
其中 type 覆盖了类、结构、委托、枚举和接口; typevar 目标名称为使用泛型的结构指定类型参数。

特性目标
eventfield
methodparam
propertyreturn
typetypevar
assemblymodule

7、全局特性

通过使用 assembly 和 module 目标名称来使用显式目标说明符把特性设置在程序集或模块级别。

  • 程序集级别的特性必须放置在任何命名空间之外,并且通常放置在 AssemblyInfo.cs 文件中。
  • AssemblyInfo.cs 文件通常包含有关公司、产品以及版权信息的元数据。

AssemblyInfo.cs 文件中代码段:

[assembly: AssemblyTitle("SuperWidget")]
[assembly: AssemblyDescription("Implements the SuperWidget product.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("McArthur Widgets,Inc.")]
[assembly: AssemblyProduct("Super Widget Deluxe")]
[assembly: AssemblyCopyright("Copyright McArthur Widgets 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

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

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

相关文章

babycrypt 自己出的第一道逆向题目 WP

Patch掉反调试 先进行了Base32解密,之后是RC4加密 Base32编码表是RC4加密后存储的,动调得到 动调可以看出,经过base32编码密文会在首部添加M7WGC76B 之后密文进行RC4加密 动调得到第二处RC4加密的密钥 解密过程 def rc4(data, key): S l…

面试题:分布式事务有哪些方案及运用场景

一、分布式事务概述 分布式事务是指涉及多个不同资源或数据库的事务处理,这些资源或数据库分布在不同的网络节点上,通过协调器将多个事务组合成一个分布式事务。分布式事务的目的是确保多个事务操作要么全部成功,要么全部失败,保…

白嫖Tesla T4 GPU玩转Stable Diffusion Webui

想要玩stable diffusion,算力不可少,白嫖google colab Tesla T4 GPU 玩转Stable Diffusion Webui 1、google colab上安装stable diffusion webui https://colab.research.google.com/drive/1qL5eD2VESnop8mrbFcHzMmfzqzmRMMF4?uspsharing 在google col…

提高代码调试能力——IDEA debug技巧

一、文章概述 idea debug调试的一些方法 二、按键简单介绍 如上如是debug时的按钮,标上序号便于说明。 1、重新开始调试 图中是已开是debug模式,不管你此时调试到哪个地方,此时点击1就可以重新开始运行程序调试:等价于&#x…

vue配置反向代理的使用

反向代理:常用于生产环境,项目部署时服务器的配置。 反向代理:同样创建一个代理服务器,用于接收客户端发送的请求,再将请求转发给内部网络上的服务器,从服务器中获取数据并返回给客户端。也就是 代理服务端…

一文了解:计算机视觉领域下自监督学习方法原理

计算机视觉领域下自监督学习方法原理 导语为什么在计算机视觉领域中进行自我监督学习? 自监督学习方法Generative methodsBEiT 架构 Predictive methodsContrastive methodsBootstraping methodsSimply Extra Regularization methods 导语 自监督学习是一种机器学习…

【NLP】从双曲面到双曲几何庞加莱盘

一、说明 在研究双曲空间的时候,不能不遇到双曲面的问题。双曲几何在什么样的双曲面建立?其它几何元素在双曲面的表现。庞加莱盘不是双曲几何的一部分,而是一个投影平面,自然语言处理中,图网络不是卷积神经网络。本篇从双曲方程开始,展开双曲空间的探讨。 二、双曲面总论…

数据库系统概述——第四章 数据库安全性(知识点复习+练习题)

🌟博主:命运之光 🦄专栏:离散数学考前复习(知识点题) 🍓专栏:概率论期末速成(一套卷) 🐳专栏:数字电路考前复习 🦚专栏&am…

【汤4操作系统】深入掌握操作系统-输入输出系统篇

第五章 输入输出系统 I/O系统简介 设备管理对象:主要是IO设备 设备管理的基本任务:完成用户提出的IO请求,提高IO速率以及改善IO设备的利用率 主要功能有: 隐藏物理设备细节。IO系统对IO设备进行适当的抽象,以隐藏掉物…

selenium 要点击的元素被其他元素遮挡 or 无法找到非可视范围内的元素

selenium 无法找到非可视范围内的元素 org.openqa.selenium.StaleElementReferenceException: The element reference of is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed se…

Java根据word模板生成word文档并转成PDF文件

1. 处理word模板 1.1 定义word模版 1.2 定义完我们的模板之后,我们要将文档保存为xml的格式 定义完我们的模板之后,我们要将文档保存为xml的格式 1.3 xml格式化 生成的xml格式看起来比较乱,没有层次感, 所以需要格式化一下 格式化 1.4 修改xml 基础信息…

TestNG官方文档中文版

TestNG官方文档中文版(1) -介绍 T e s t NG 的 官 方 文 档 请 见 :http://testng.org/doc/documentation-main.html 1 介绍 T e s t N G 是 一 个 设 计 用 来 简 化 广 泛 的 测 试 需 求 的 测 试 框 架 , 从 单 元 测 试 (隔 离测试- 个类)到集成测试(测试由有…

Visio2013绘制任意曲线

曲线上蓝色的‘弯曲点‘,随着拉伸曲线,它自己会增减,这里要和’连接点‘区分开,连接点是用来连接别的图形的。

git通过ssh代理连接github(gitee不支持),并更改端口

文章目录 需求github使用ssh代理的方案gitee无法实现ssh代理gitee的暂时解决方案 参考 需求 git clone github/gitee远程仓库,使用ssh协议,并且走本地的http代理(端口3128)。 运行环境是Ubuntu 20.04。 github使用ssh代理的方案 修改~/.ssh/config文…

解决containerd+k8s集群搭建镜像拉取不到的问题

解决containerdk8s集群搭建镜像拉取不到的问题 下载离线镜像导入镜像初始化集群安装calico插件安装MetalLB部署一个nginx应用并暴露端口 之前我写了一篇containerdk8s搭建集群的文章,文章地址: https://blog.csdn.net/m0_51510236/article/details/1308…

系统架构设计师-系统工程与信息系统基础(3)

一、企业信息化与电子商务 1、企业资源计划(ERP) ERP是由MRP(物料需求计划)、MRPll(制造资源计划)一步步演化而来。 MARPll:核心是物流,主线是计划。 ERP:打通了供应链&a…

小白也能玩转Docker:应用部署、迁移与备份

目录 1、应用部署 1.1、Mysql 1.2、Ngixn 1.3、Redis 1.4、RabbitMQ 1.5、Elasticsearch 1.6、Zookeeper 2、迁移与备份 2.1容器保存为镜像 2.2镜像备份 2.3镜像恢复与迁移 1、应用部署 1.1、Mysql 拉取mysql的镜像: docker pull mysql:5.7 为mysql镜…

C语言深度刨析(二)——符号

文章目录 前言注释符号几个似非而是的注释问题y x/*p如何编写出出色的注释 接续符和转义符单引号、双引号逻辑运算符位运算符左移和右移0x01<<23的值为多少&#xff1f; 花括号、--操作符2/(-2)的值是多少&#xff1f;运算符的优先级运算符的优先级表一些容易出错的优先…

JavaEE课程设计(项目详细设计)

目录 项目文件组织结构 springbootschemaApplication dao controller application.yml entity annotation interceptor config 项目文件组织结构 这是后端部分的源码结构图 springbootschemaApplication springbootschemaApplication是整个项目的入口 package …

AI热门垂直领域大模型盘点(附论文)

上回分享了一些通用大模型的使用感受&#xff0c;今天咱们就来聊聊垂直领域大模型&#xff0c;照旧附上论文资料&#xff0c;同学们自取哈&#xff01; 其实照目前的趋势来看&#xff0c;垂直领域大模型的未来发展是要比通用大模型好的&#xff0c;一是通用大模型有GPT4这座难…