【C#进阶】C# 反射

news2024/11/25 19:23:41
序号系列文章
11【C#基础】C# 预处理器指令
12【C#基础】C# 文件与IO
13【C#进阶】C# 特性

文章目录

  • 前言
  • 1,反射的概念
  • 2,使用反射访问特性
  • 3,反射的用途
  • 4,反射的优缺点比较
    • 4.1 优点:
    • 4.2 缺点:
  • 5,System.Reflection 命名空间
    • 5.1 获取程序集中的信息
    • 5.2 获取程序集中的类型
    • 5.3 获取程序集中的成员
    • 5.4 创建类型的实例对象
  • 结语

前言

✋ 大家好,我是writer桑,本章为大家介绍 C# 中的反射


1,反射的概念

反射指的是程序可以访问,检测和修改它本身状态或行为的一种行为。 其中访问的目标包括程序集1、模块和类型对象等。可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型,然后调用其方法或访问器字段和属性。反射行为也常常用来访问应用在程序上的特性。

代码示例:(简单展示)

using System;
using System.Reflection;

public class Example
{
    static void Main()
    {
        // 使用反射获取程序集的信息:
        Assembly info = typeof(int).Assembly;
        Console.WriteLine(info);
    }
}

运行结果:
在这里插入图片描述
在上例中,使用 typeof 方法获取已加载的 int 程序集的完整名称。

2,使用反射访问特性

在前面的一章中,我们讨论到了 C# 使用反射访问特性的操作。在本章中就可以使用反射的操作来访问 Example 类中的元数据。

代码示例:

using System;

[System.AttributeUsage(System.AttributeTargets.Class |
 System.AttributeTargets.Struct)
]
public class AuthorAttribute : System.Attribute
{
    public string name;		
    public double age;

    // 构造函数
    public AuthorAttribute(string name)
    {
        this.name = name;
        age = 11;
    }
}

[Author("writer桑", age = 21)]
public class Example
{
    // Example类成员
}
 
public class Program
{
    static void Main()
    {
        // 访问 Example 类应用的特性             
        Type type = typeof(Example);

        // 遍历输出 
        foreach(Object attributes in type.GetCustomAttributes(true))
        {
            AuthorAttribute author = (AuthorAttribute)attributes;
            Console.WriteLine(author.age);
            Console.WriteLine(author.name); 
        }
    }
}

运行结果:
在这里插入图片描述

3,反射的用途

反射的用途可以总结为以下几点:

  1. 需要访问程序中的元数据的特性时。(点击了解更多)
  2. 检查和实例化程序集中的类型时。
  3. 在运行时构建新的类型,比如使用 System.Reflection.Emit 中的类。(点击了解更多)
  4. 执行后期绑定,访问在运行时创建的类型上的方法时。(点击了解更多)

4,反射的优缺点比较

反射的优缺点比较:

4.1 优点:

  • 反射是运行期的操作,提高了程序的灵活性和扩展性。
  • 降低耦合度2,提高自适应能力。
  • 允许动态的创建和使用对象,无需提前硬编码3目标对象。

4.2 缺点:

  • 性能较低,反射是运行期4的代码,在性能方面不如直接的编译型5代码。
  • 可读性较低,使用反射会使得程序本身的逻辑变得复杂,在可读性方面不如直接的代码来的简洁。
  • 维护成本变高,反射是一种绕过了源代码的技术, 因而在维护的方面难度较高。

5,System.Reflection 命名空间

System.Reflection 命名空间中包含通过检测托管代码中程序集、模块、成员、参数和其他实体的元数据来检索其相关信息的类型。同时也可以用于操作加载类型的实例,例如钩子函数6或调用方法。在 C# 中,实现反射操作常常需要用到 System.Reflection 命名空间中的类和方法。

列举一些 System.Reflection 命名空间中常用的反射操作:

5.1 获取程序集中的信息

System.Reflection 命名空间中的 Assembly.FullName 等属性可以用来获取程序集中的信息。

代码示例:

using System;
using System.Reflection;

public class Example
{
    private int factor;
    public Example(int f)
    {
        factor = f;
    }

    public int SampleMethod(int x)
    {
        Console.WriteLine($"实例方法的执行:({x})");
        return x * factor;
    }

    public static void Main()
    {
        Assembly assem = typeof(Example).Assembly;

        Console.WriteLine($"程序集的全程:{assem.FullName}");

        // 可以使用 AssemblyName 类型解析完整名称。
        AssemblyName assemName = assem.GetName();
        Console.WriteLine($"名称: {assemName.Name}");

        //从程序集创建一个对象,并传入正确的数字
        //构造函数的参数类型。
        Object o = assem.CreateInstance("Example", false, BindingFlags.ExactBinding, null, new Object[] { 2 }, null, null);

        // 对对象的实例方法进行晚绑定调用。
        MethodInfo m = assem.GetType("Example").GetMethod("SampleMethod");
        Object ret = m.Invoke(o, new Object[] { 42 });
        Console.WriteLine($"示例方法的返回值为:{ret}");

        Console.WriteLine($"程序集入口点:{assem.EntryPoint}");
    }
}

运行结果:
在这里插入图片描述

5.2 获取程序集中的类型

System.Reflection 命名空间中的 Assembly.GetExportedTypes 方法可以用来获取程序集中定义的公共类型,这些公共类型在程序集外可见。

代码示例:

using System;
using System.Reflection;

public class PublicClass
{
    public class PublicNestedClass { }

    protected class ProtectedNestedClass { }

    internal class FriendNestedClass { }

    private class PrivateNestedClass { }
}

public class Example
{
    public static void Main()
    {
        // 获取程序集中定义的公共类型 
        foreach (Type t in typeof(Example).Assembly.GetExportedTypes())
        {
            Console.WriteLine(t);
        }
    }
}

运行结果:
在这里插入图片描述

5.3 获取程序集中的成员

System.Reflection 命名空间中的 MemberInfo 类中的属性和方法可以用来获取有关成员属性的信息并提供对成员元数据的访问权限。

代码示例:

using System;
using System.Reflection;

public class Example
{
    // 显示应用到指定成员的自定义属性 
    public static void DisplayAttributes(Int32 indent, MemberInfo mi)
    {
        // 获取自定义属性集;如果不存在,则返回。
        object[] attrs = mi.GetCustomAttributes(false);
        if (attrs.Length == 0) { return; }

        // 显示应用于该成员的自定义属性。
        Display(indent + 1, "属性:");
        foreach (object o in attrs)
        {
            Display(indent + 2, "{0}", o.ToString());
        }
    }

    // 显示一个缩进的格式化字符串。 
    public static void Display(Int32 indent, string format, params object[] param)
    {
        Console.Write(new string(' ', indent * 2));
        Console.WriteLine(format, param);
    }

    public static void Main()
    {
        //该变量保存缩进的数量, 显示每一行信息时使用。
        Int32 indent = 0;

        // 显示加载到这个 AppDomain 第一个 程序集的信息。
        Assembly b = AppDomain.CurrentDomain.GetAssemblies()[0];
        Display(indent, "程序集: {0}", b);

        // 显示从此程序集导出的 第一个 类型的相关信息。 
        indent += 1;
        Type t = b.GetExportedTypes()[0];

        Display(0, "");
        Display(indent, "类型: {0}", t);

        // 遍历显示成员及其自定义属性。
        indent += 1;
        foreach (MemberInfo mi in t.GetMembers())       // GetMembers 方法
        {
            Display(indent, "成员: {0}", mi.Name);
            DisplayAttributes(indent, mi);

            // 如果成员是一个方法,显示它的参数信息。
            if (mi.MemberType == MemberTypes.Method)
            {
                foreach (ParameterInfo pi in ((MethodInfo)mi).GetParameters())
                {
                    Display(indent + 1, "参数: 类型={0}, 名字={1}", pi.ParameterType, pi.Name);
                }
            }

            // 如果成员是一个属性,显示关于属性的访问方法的信息。 
            if (mi.MemberType == MemberTypes.Property)
            {
                foreach (MethodInfo am in ((PropertyInfo)mi).GetAccessors())
                {
                    Display(indent + 1, "访问器方法: {0}", am);
                }
            }
        }
    }
}

运行结果:
在这里插入图片描述

5.4 创建类型的实例对象

System.Reflection 空间中的 Assembly.CreateInstance 方法可以用来获取包含当前执行的代码的程序集,以此来创建类型的实例对象。

代码示例:

using System;
using System.Reflection;

public class Person
{
    private string _name;

    public Person()
    { }

    public Person(string name)
    {
        this._name = name;
    }

    public string Name
    {
        get { return this._name; }
        set { this._name = value; }
    }

    public override string ToString()
    {
        return this._name;
    }
}

public class Example
{
    public static void Main()
    {
        Assembly assem = typeof(Person).Assembly;

        // 创建 Person 类的实例化对象 
        Person p = (Person)assem.CreateInstance("Person");

        if (!(p == null))
        {
            p.Name = "John";
            Console.WriteLine($"实例化值为'{p}'的{p.GetType().Name}对象");
        }
        else
        {
            Console.WriteLine("无法实例化Person对象。");
        }
    }
}

运行结果:
在这里插入图片描述

点击了解更多 System.Reflection 命名空间的使用。


结语

👋 以上就是关于 C# 反射的介绍啦,希望对大家有所帮助。感谢大家的支持。


  1. 程序集(assembly):是一个及一个以上托管模块,以及一些资源文件的逻辑组合。在 .NET 中,dll与exe文件都是程序集。 ↩︎

  2. 耦合性(或称耦合力或耦合度):是一种软件度量,是指一程序中,模块及模块之间信息或参数依赖的程度。 ↩︎

  3. 硬编码:是将数据直接嵌入到程序或其他可执行对象的源代码中的软件开发实践,与从外部获取数据或在运行时生成数据不同。 ↩︎

  4. 运行期:是把编译后的文件交给计算机执行,直到程序运行结束。 ↩︎

  5. 编译期:是指把源码交给编译器编译成计算机可以执行的文件的过程。 ↩︎

  6. 钩子函数:是 Windows 消息处理机制的一部分,是指在程序正常运行中接受信息之前预先启动的函数,用来检查和修改传给该程序的信息,(钩子)实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。 ↩︎

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

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

相关文章

吲哚菁绿-巯基,ICG-SH,科研级别试剂,吲哚菁绿可用于测定心输出量、肝脏功能、肝血流量,和对于眼科血管造影术。

ICG-THIOL,吲哚菁绿-巯基 中文名称:吲哚菁绿-巯基 英文名称:ICG-THIOL 英文别名:ICG-SH 性状:绿色粉末 溶剂:溶于二氯甲烷等其他常规有机溶剂 稳定性:冷藏保存,避免反复冻融。 存储条件&…

搭建SpringBoot多模块微服务项目脚手架(二)

搭建SpringBoot多模块微服务项目脚手架(二) 文章目录搭建SpringBoot多模块微服务项目脚手架(二)1.概述2.封装 MybatisPlus2.1.封装MybatisPlus1.安装依赖2.安装lombok插件3.配置数据库链接信息2.2.创建公共子模块1.创建公共模块common2.创建common_utils模块3.创建service_base…

【C++知识点】文件操作

✍个人博客:https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 📚专栏地址:C/C知识点 📣专栏定位:整理一下 C 相关的知识点,供大家学习参考~ ❤️如果有收获的话,欢迎点赞👍…

【六祎 - 前端】npm是什么?npm是网站、注册表、命令行工具组成;windows安装nvm;使用nvm安装npm;

nvm管理并安装npmnpm中文文档npm是什么?npm 由三个独立的部分组成:快速入门命令行npm用法npm配置查找包(package)windows安装nvm使用nvm安装npmps:切换版本下载npm之后的一些配置(Optional)npm中文文档 →_→点我查看…

Java的stream流

Java 8中引入的新特性,stream流通过与Lambda表达式结合,采用函数式编程,简化数组、集合操作,提高效率。 我们操作一个集合,就把他看作一个流,整个流依次执行,(可以类比为一个管道&a…

企业官网怎么做?

企业官网是企业展示形象和吸引潜在客户的重要渠道之一,因此如何打造一款优秀的企业官网显得尤为重要。本文将从策划、设计、开发和上线等方面,为您介绍企业官网的制作步骤。 一、策划 1.明确目标 企业官网的制作需要明确目标,即确定官网的主…

4. SSM 整合

文章目录1. 引言2. 创建工程3. SSM 整合2. 统一结果封装3. 统一异常处理3.1 异常处理器3.2 项目异常处理方案3.2.1 异常分类3.2.2 异常解决方案3.2.3 异常解决方案的具体实现4. 前后台协议联调4.1 列表功能4.2 添加功能4.3 修改功能4.4 删除功能5. 拦截器5.1 拦截器概念1. 引言…

mysql数据库之innodb存储引擎架构之内存架构

一、逻辑存储结构 mysql5.5版本开始,默认使用innodb存储引擎,它擅长事务处理,具有崩溃恢复特性,在日常开发中使用非常广泛。 架构图(左侧为内存架构,右侧为磁盘架构) 二、 内存架构。 1、缓冲…

SpringBoot使用Redis实现缓存

目录 实现步骤 1. 在 pom.xml 配置文件中添加如下依赖 2. 在 application.properties 中添加如下配置 3. 新建 RedisConfig.class,继承 CachingConfigurerSupport,添加如下方法 4. 新建 RedisService.class 添加如下方法 注意:cacheKey…

看完书上的栈不过瘾,为什么不动手试试呢?

一.栈的基本概念1.栈的定义栈(Stack):是只允许在一端进行插入或删除的线性表。首先栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。其中注意几点:栈顶(Top):线性表…

2023年新三板产品及服务研究报告

第一章 概述 全国中小企业股份转让系统(英语:National Equities Exchange and Quotations,缩写NEEQ),简称股转系统,是第三家全国性证券交易场所,因挂牌企业均为高科技企业而不同于原转让系统内…

软件测试12

一 Linux命令的共通知识点 1.通配符的使用 通配符:又叫文件名替换符号,符号具备特殊含义,例如:文件名:test,通配符可以写成???或者* *:代表可以匹配任意长度的文件名(all所有&am…

xxl-job registry fail

解决方法: 1、检查nacos是否正确,一定要注意格式,一般都是addersses的地址问题,一定的要加/不然找不到,本机就不要使用ip了,用localhost。 xxl: job: admin: addresses: http://localhost:8080/xxl-job-ad…

【java】 java开发中 常遇到的各种难点 思路方案

文章目录逻辑删除如何建立唯一索引唯一索引失效问题加密字段模糊查询问题maven依赖冲突问题(jar包版本冲突问题)sql in条件查询时 将结果按照传入顺序排序作为一个开发人员 总会遇到各种难题 本文列举博主 遇见/想到 的例子 ,也希望同学们可以…

【LVGL移植】STM32F1基于STM32CubeMX配置硬件SPI驱动1.8寸TFT ST7735S跑LVGL图形demo

【LVGL移植】STM32F1基于STM32CubeMX配置硬件SPI驱动1.8寸TFT ST7735S屏幕跑LVGL图形demo🎬运行LVGL 按键组件demo ✨基于STM32CubeMX配置工程是因为方便移植,只要是STM32芯片,拿到我的这个工程源码就可以根据自己的stm32芯片,自…

操作系统复试

2017软学 给出操作系统的定义,分别从资源管理,任务调度,用户接口等三个方面论述操作系统的职能 操作系统是位于硬件层之上、所有其他系统软件层之下的一个系统软件,使得管理系统中的各种软件和硬件资源得以充分利用,方…

MATLAB——求连续系统的响应

题目: 已知RC一阶高通电路图的系统函数H(s)为 H(s)UR(S)U(S)RRR1SCsRCsRC1H(s)\frac {UR(S)}{U(S)}R\frac {R}{R\frac {1}{SC}}\frac {sRC}{sRC1}H(s)U(S)UR(S)​RRSC1​R​sRC1sRC​ 其中:R200Ω ,C0.47μF 。求其幅度频率响应与相位频率响应…

公网NAT网关与VPC NAT网关介绍与实践

NAT网关介绍 NAT网关是一种网络地址转换服务,提供NAT代理(SNAT和DNAT)能力。 公有云NAT分为公网NAT网关和VPC NAT网关。 1)公网NAT网关:提供公网地址转换服务。 2)VPC NAT网关:提供私网地址转换…

商品获价API调用说明:获取商品历史价格信息 代码分享

接口名称:item_history_price公共参数名称类型必须描述keyString是调用key(获取测试key)secretString是调用密钥api_nameString是API接口名称(包括在请求地址中)[item_search,item_get,item_search_shop等]cacheString…

Linux磁盘空间占满了

Linux服务器没有安装很多东西,但是硬盘空间爆满了。。。 df -h 查看硬盘空间,发现使用了99%。 刚开始以为是日志文件的占用的,删除了linux日志文件,发现作用不大,只多了几G。 不妨试试下面的命令 lsof L1 发现了有个…