C#反射(Reflection)详解

简介:

反射是.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;
    }
}

利用反射获取类型

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

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

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

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

还可以通过属性名称获取

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

获取私有实例

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

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

获取方法

使用反射 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}");
        }
    }

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

  1. ToString() :将对象转换为字符串

  1. Equals(Object):确定该对象是否等于另一个对象

  1. GetHashCode():获取对象的哈希代码

  1. GetType():获取对象的类型

  1. Finalize():在垃圾回收器回收对象之前执行清理操作

  1. MemberwiseClone():创建当前对象的浅表副本

给属性赋值

    [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

字段赋值

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

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

    [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:爱情公寓

获取程序集

程序集是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");
    }

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

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

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

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

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

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C# 反射是指在运行时动态地获取类的信息,通过反射可以获取类的属性、方法、事件等信息,以及动态创建对象、调用方法、获取值等操作。这使得我们能够在运行时动态地编写代码,可以写出更加灵活和可扩展的程序。 C# 反射的核心是 `System.Reflection` 命名空间,该命名空间包含了许多与反射相关的类和接口,比如 `Type` 类、`MethodInfo` 类、`PropertyInfo` 类等。 下面是一些常用的反射操作: 1. 获取类型信息 可以使用 `typeof` 关键字或者 `Type.GetType()` 方法来获取类型的信息。`typeof` 关键字用于获取编译时已知的类型信息,而 `Type.GetType()` 方法则可以通过类型名称获取运行时的类型信息。 ```csharp // 获取 System.String 类型的信息 Type type1 = typeof(System.String); // 获取指定类型名称的信息 Type type2 = Type.GetType("System.String"); ``` 2. 获取成员信息 可以使用 `Type.GetMembers()` 方法获取类型的所有成员信息,包括属性、方法、字段、事件等。也可以使用 `Type.GetMethod()`、`Type.GetProperty()`、`Type.GetField()`、`Type.GetEvent()` 等方法获取指定成员的信息。 ```csharp Type type = typeof(Person); // 获取类型的所有成员信息 MemberInfo[] members = type.GetMembers(); // 获取指定属性的信息 PropertyInfo property = type.GetProperty("Name"); // 获取指定方法的信息 MethodInfo method = type.GetMethod("SayHello"); // 获取指定字段的信息 FieldInfo field = type.GetField("Age"); // 获取指定事件的信息 EventInfo eventInfo = type.GetEvent("PropertyChanged"); ``` 3. 动态创建对象 可以使用 `Activator.CreateInstance()` 方法动态创建对象,也可以使用 `Type.InvokeMember()` 方法调用构造函数来创建对象。 ```csharp Type type = typeof(Person); // 使用 Activator.CreateInstance() 方法创建对象 Person person1 = (Person)Activator.CreateInstance(type); // 使用 Type.InvokeMember() 方法调用构造函数创建对象 Person person2 = (Person)type.InvokeMember(null, BindingFlags.CreateInstance, null, null, new object[] { "Tom", 18 }); ``` 4. 调用成员 可以使用 `MethodInfo.Invoke()` 方法调用方法,也可以使用 `PropertyInfo.SetValue()` 方法设置属性的值,使用 `FieldInfo.SetValue()` 方法设置字段的值。 ```csharp Type type = typeof(Person); Person person = new Person("Tom", 18); // 调用方法 MethodInfo method = type.GetMethod("SayHello"); method.Invoke(person, null); // 设置属性的值 PropertyInfo property = type.GetProperty("Name"); property.SetValue(person, "Jerry", null); // 设置字段的值 FieldInfo field = type.GetField("Age"); field.SetValue(person, 20); ``` 以上是 C# 反射的一些基本操作,反射的应用非常广泛,可以用来实现插件式开发、ORM 映射等功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱吃香蕉的阿豪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值