【C#进阶】C# 反射

这篇具有很好参考价值的文章主要介绍了【C#进阶】C# 反射。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

前言

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


1,反射的概念

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

代码示例:(简单展示)

using System;
using System.Reflection;

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

运行结果:
c# 反射工具类,C#/.NET系列文章,c#,开发语言,微软,.netcore
在上例中,使用 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); 
        }
    }
}

运行结果:
c# 反射工具类,C#/.NET系列文章,c#,开发语言,微软,.netcore

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}");
    }
}

运行结果:
c# 反射工具类,C#/.NET系列文章,c#,开发语言,微软,.netcore

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);
        }
    }
}

运行结果:
c# 反射工具类,C#/.NET系列文章,c#,开发语言,微软,.netcore

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);
                }
            }
        }
    }
}

运行结果:
c# 反射工具类,C#/.NET系列文章,c#,开发语言,微软,.netcore

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对象。");
        }
    }
}

运行结果:
c# 反射工具类,C#/.NET系列文章,c#,开发语言,微软,.netcore

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


结语

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


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

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

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

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

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

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

到了这里,关于【C#进阶】C# 反射的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C#进阶-IIS服务器发布ASP.NET项目

    对于云服务器,程序员一般不会陌生,如果项目需要发布到现网,那么服务器是必不可缺的一项硬性条件,那么如何在云服务器上部署一个项目,需要做哪些配置准备,下面就由本文档为大家讲解,本篇以 IIS服务器 发布 ASP.NET 项目为例。 本地用 Visual Studio 打开一个可运行的

    2024年02月01日
    浏览(45)
  • 2023-06-10 Untiy进阶 C#知识补充1——.Net介绍

    一、.Net 介绍 ​ 微软的 .Net 既不是编程语言也不是框架,是类似于互联网时代、次时代、21世纪、信息时代之类的宣传口号 ​ 它是一整套技术体系的统称,或者说它是微软提供的技术平台的代号。包含的内容有: 框架体系: .Net Framework .Net Core Mono 等等 开发语言: C#(C# 是

    2024年02月09日
    浏览(42)
  • 个人用C#编写的壁纸管理器 - 开源研究系列文章

    今天介绍一下笔者自己用C#开发的一个小工具软件:壁纸管理器。 开发这个小工具的初衷是因为Windows操作系统提供的功能个人不满意,而且现在闲着,所以就随意写了个代码。如果对读者有借鉴参考作用就更好了,能够直接代码段复用即可。这个壁纸管理器也比较简单,基于

    2024年02月13日
    浏览(29)
  • C#利用自定义特性以及反射,来提大型项目的开发的效率

      在大型项目的开发过程中,需要多人协同工作,来加速项目完成进度。 比如一个软件有100个form,分给100个人来写,每个人完成自己的Form.cs的编写之后,要在Mainform调用自己写的Form。 如果按照正常的Form form1 = new Form()这种写法来构造窗口的话,相当于每个人都要改动Mainfo

    2024年02月14日
    浏览(33)
  • 使用C#的窗体显示与隐藏动画效果方案 - 开源研究系列文章

    今天继续研究C#的WinForm的显示动画效果。 上次我们实现了无边框窗体的显示动画效果(见博文:基于C#的无边框窗体动画效果的完美解决方案 - 开源研究系列文章 ),这次介绍的是未在任务栏托盘中窗体的显示隐藏动画效果的实现代码。 1、 项目目录; 下面是项目目录,由基本

    2024年02月14日
    浏览(25)
  • C#程序的启动显示方案(无窗口进程发送消息) - 开源研究系列文章

    今天继续研究C#的WinForm的实例显示效果。 我们上次介绍了Winform窗体的唯一实例运行代码(见博文:基于C#的应用程序单例唯一运行的完美解决方案 - 开源研究系列文章  )。这就有一个问题,程序已经打开了,这时候再次运行该应用程序,我们的方案是将该应用的主窗体显示出

    2024年02月14日
    浏览(28)
  • 基于C#的无边框窗体动画效果的完美解决方案 - 开源研究系列文章

           最近在整理和编写基于C#的WinForm应用程序,然后碰到一个其他读者也可能碰到的问题,就是C#的Borderless无边框窗体的动画效果问题。        在Visual Studio 2022里,C#的WinForm程序提供了Borderless无边框窗体的样式效果,但是它没提供在无边框窗体下,窗体的载入、最小

    2024年02月15日
    浏览(29)
  • .net C#反编译及脱壳常用工具--小结

    1、Reflector --微软自家工具--推荐        Reflector是 最为流行的.Net反编译工具 。Reflector是由微软员工Lutz Roeder编写的免费程序。Reflector的出现使·NET程序员眼前豁然开朗,因为这个免费工具可以将·NET程序集中的中间语言反编译成C#或者Visual Basic代码。除了能将IL转换为C#或

    2024年02月04日
    浏览(26)
  • 基于C#的应用程序单例唯一运行的完美解决方案 - 开源研究系列文章

    今次介绍一个应用程序单例唯一运行方案的代码。 我们知道,有些应用程序在操作系统中需要单例唯一运行,因为程序多开的话会对程序运行效果有影响,最基本的例子就是打印机,只能运行一个实例。这里将笔者单例运行的代码共享出来,需要的读者请自己复用该代码到自

    2024年02月14日
    浏览(35)
  • C#语言实例源码系列-伪装文件

    专栏分享 点击跳转=Unity3D特效百例 点击跳转=案例项目实战源码 点击跳转=游戏脚本-辅助自动化 点击跳转=Android控件全解手册 众所周知,人生是一个漫长的流程,不断 克服困难 ,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思

    2023年04月18日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包