C#反射(Reflection)详解

简介: 反射是.NET中的重要机制,通过反射可以得到*.exe或*.dll等程序集内部的接口、类、方法、字段、属性、特性等信息,还可以动态创建出类型实例并执行其中的方法。反射指程序可以访问、检测和修改它本身状态或行为的一种能力。通俗一点:我们在获取其他实体类的字段名或实列,只能获取公有的,而有了反射之后可以获取私有的,可以获取他的基类等等,可以说把家底查得清清楚楚。

 简介:

反射是.NET中的重要机制,通过反射可以得到*.exe或*.dll等程序集内部的接口、类、方法、字段、属性、特性等信息,还可以动态创建出类型实例并执行其中的方法。

反射指程序可以访问、检测和修改它本身状态或行为的一种能力。

通俗一点:我们在获取其他实体类的字段名或实列,只能获取公有的,而有了反射之后可以获取私有的,可以获取他的基类等等,可以说把家底查得清清楚楚

案例

创建一个学生类,里面有公有姓名,私有年龄但提供get方法,以及Home住址不提供get方法

namespace Project;
public class Student
{
    //公开信息id
    public int id { get; set; }
    //公开信息Name
    public String Name;
    //私有信息年龄
    private int Age;
    //保密信息家庭住址
    private String Home;
    //有参无参构造方法
    public Student(){}
    public Student(String name, int age)
    {
        Name = name;
        Age = age;
    }
    //获取年龄方法
    public int Getage()
    {
        return this.Age;
    }
}

image.gif

利用反射获取类型

在用反射对类进行操作之前,我们要先获取到类,下面是反射获取类的两种方式👇

[Test]
    public void TestGetType()
    {
        //通过typeof运算符获取type类型
        Type type = typeof(Student);
        Console.WriteLine("type="+type);
        //通过实例对象获取
        StuDdentInfo obj = new StuDdentInfo();
        Type type2 = obj.GetType();
        Console.WriteLine("type2="+type2);
    }

image.gif

控制台输出,成功获取到了类型

image.gif

获取Properties

首先变量类型声明方式创建一个 Type 类型的变量 type,表示 Student 类型。接着,使用反射 API 的 GetProperties() 方法获取 Student 类型的所有公共属性(包括只读、读写)、静态属性和实例属性等信息,然后存储在Students 变量中。

最后,使用 foreach 遍历每个属性信息对象

[Test]
    public void TestProperty()
    {
        Type type = typeof(Student);
        var Students = type.GetProperties();
        foreach (var student in Students)
        {
            Console.WriteLine($"名称:{student.Name},类型:{student.GetMethod}");
        }
}

image.gif

image.gif

还可以通过属性名称获取

[Test]
    public void TestProperty()
    {
        Type type = typeof(Student);
        var property = type.GetProperty("id");
        Console.WriteLine($"名称:{property.Name},类型:{property.PropertyType}");
    }
//控制台返回:名称:id,类型:System.Int32

image.gif

获取私有实例

反射最牛的地方就是他可以获取私有方法与实列

BindingFlags.Instance 表示只获取实例方法

BindingFlags.NonPublic 表示只获取非公共方法

首先使用 C# 变量类型声明方式创建一个表示 Student 类型的 Type 类型变量 type。接着,利用 type 变量使用反射 API 的 GetFields() 方法找到所有 Student 类型的非公共实例字段,存储在 fieldInfos 变量中。

[Test]
    public void TestField()
    {
        Type type = typeof(Student);
        var fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
        foreach (var fieldInfo in fieldInfos)
        {
            Console.WriteLine($"名称:{fieldInfo.Name},类型:{fieldInfo.FieldType}");
        }
    }

image.gif

image.gif

获取方法

使用反射 API 获取 Student 类型的所有实例方法(包括公共和非公共的),然后赋值给 methods 变量

BindingFlags.Instance 表示只获取实例方法

BindingFlags.Public 表示只获取公共方法

BindingFlags.NonPublic 表示只获取非公共方法

[Test]
    public void TestMethod()
    {
        var type = typeof(Student);
        var methods  = type.GetMethods(
            BindingFlags.Instance |BindingFlags.Public| BindingFlags.NonPublic
            );
        foreach (var methodInfo in methods)
        {
            Console.WriteLine($"名称:{methodInfo.Name},类型:{methodInfo.ReturnType}");
        }
    }

image.gif

控制台打印中有Student类中的方法,还有GetType、Finalize、ToString等方法,因为这六个方法继承Object方法。

    1. ToString() :将对象转换为字符串
      1. Equals(Object):确定该对象是否等于另一个对象
        1. GetHashCode():获取对象的哈希代码
          1. GetType():获取对象的类型
            1. Finalize():在垃圾回收器回收对象之前执行清理操作
              1. MemberwiseClone():创建当前对象的浅表副本

              image.gif

              给属性赋值

              [Test]
                  public void TestOpenProperty()
                  {
                      Type type = typeof(Student);
                      var propertyInfo = type.GetProperty("id");
                      var instance = Activator.CreateInstance(type);
                      propertyInfo.SetValue(instance,1011);
                      var value = propertyInfo.GetValue(instance);
                      Console.WriteLine(value);
                  }
              //输出1011

              image.gif

              字段赋值

              一般来说,方法的私有字段都是在方法内部使用的,哪怕我们new一个方法,用方法也是点不出来私有字段的,比如student的Home是私有字段,下面new一个Student类,提示里并没有Home字段。

              image.gif

              有了反射,我们可以获取到类里的私有字段,还可以对其进行赋值

              [Test]
                  public void TestOperationField()
                  {
                      Type type = typeof(Student);
                      var fieldInfo = type.GetField("Home", BindingFlags.Instance | BindingFlags.NonPublic);
                      var instance = Activator.CreateInstance(type);
                      fieldInfo.SetValue(instance,"爱情公寓");//给Home赋值
                      var obj = fieldInfo.GetValue(instance);//获取Home的值
                      Console.WriteLine("myHome:"+obj);
              }
              //输出:myHome:爱情公寓

              image.gif

              获取程序集

              程序集是C#程序构建后生成的二进制文件,其中包含了C#代码编译后产生的中间语言(Intermediate Language,简称IL)以及元数据信息。程序集可以是可执行文件(.exe文件)或动态链接库文件(.dll文件),它们被用于将C#源代码编译成.NET平台上的可执行文件。程序集包含了类、方法、属性、事件等编译生成的元素,同时也可能包含其他资源文件,如图像、声音、文本等。

              通过反射获取程序集的方法👇

              [Test]
                  public void TestAssembly()
                  {
                      //通过项目名称加载程序集
                      var assembly = Assembly.Load("Project");
                      //通过dll的路径加载程序集
                      var loadFile = Assembly.LoadFile(@"D:\project\c#\Solution\Project\bin\Debug\net6.0\Project.dll");
                  }

              image.gif

              加载程序集后可以看见此程序集的dll路径,版本号,解决方案,类名等等信息

              image.gif

              然后我们可以通过Assembly.GetExecutingAssembly()来获取程序集的信息

              Assembly.GetExecutingAssembly().GetName().Name;可以获取程序集的解决方案名称project

              image.gif

              同时还可以通过反射获取的程序集来实例化我们的类

              //解决方案.类名称 , false:忽略大小写,可以不写var instance = loadFile.CreateInstance("Project.Student",false);

              image.gif


              目录
              相关文章
              |
              3月前
              |
              设计模式 C#
              C#反射机制实现开闭原则的简单工厂模式
              C#反射机制实现开闭原则的简单工厂模式
              18 0
              |
              4月前
              |
              存储 C# 开发者
              C# | 通过反射将对象属性展示在TreeView中
              在编程过程中,我们经常需要处理复杂的对象和数据结构。将这些数据结构展示在UI界面上是很有用的,可以帮助开发者更好地理解和分析数据。 而TreeView作为一种常见的控件,可以以树状结构的方式展示数据,非常适合用于展示层次化的对象。 本文将介绍如何使用TreeView控件展示一个对象,并且可以动态处理对象中的属性和子对象。通过本文的学习,您将学会如何更好地理解和展示数据,提高编程效率。
              34 0
              C# | 通过反射将对象属性展示在TreeView中
              |
              4月前
              |
              安全 C# 图形学
              C#的反射机制
              C#的反射机制
              |
              7月前
              |
              开发框架 缓存 安全
              C#OOP之十三 组件、程序集与反射
              C#OOP之十三 组件、程序集与反射
              38 0
              |
              7月前
              |
              开发框架 .NET Java
              C#下反射动态加载dll后如何卸载?
              C#下反射动态加载dll后如何卸载?
              |
              7月前
              |
              Oracle 架构师 关系型数据库
              C#反射应用之实现动态可配置可扩展框架的简单示例
              C#反射应用之实现动态可配置可扩展框架的简单示例
              |
              7月前
              |
              Java 关系型数据库 MySQL
              C#反射(Reflection)详解及于java反射的对比
              C#反射(Reflection)详解及于java反射的对比
              |
              9月前
              |
              C# 数据安全/隐私保护
              C#机房重构-修改密码之职责链模式+反射
              C#机房重构-修改密码之职责链模式+反射
              42 0
              |
              10月前
              |
              运维 Devops C#
              【C#编程最佳实践 十七】反射工厂最佳实践
              【C#编程最佳实践 十七】反射工厂最佳实践
              58 0
              |
              缓存 IDE API
              C#反射与特性(五):主类型成员操作
              C#反射与特性(五):主类型成员操作
              337 0
              C#反射与特性(五):主类型成员操作