20250607-C#知识:反射初探

C#知识:反射初探

1、反射相关概念

  • 程序集:编译器将源代码编译后产生的可执行的文件(.dll或.exe),一个程序集一般包含多个类
  • 元数据:描述数据特征的数据,例如类的元数据描述了这个类的类名、包含哪些成员等信息
  • 反射:程序在运行过程中能够查看自身或其他程序的元数据的行为
  • 反射作用:能够在程序运行过程中,利用类的元数据来实例化对象以及操作对象

2、 Type类(类的信息类):获取指定类的元数据

2.1 获取Type:

  1. Object类中的GetType()方法
    这种方法需要有类的对象,但一般没有这个对象
int a = 10;
Type type1 = a.GetType();
Console.WriteLine(type1);
  1. 通过类名+typeof方法
    这种方法需要类名,而且这个类能够访问到
Type type2 = typeof(int);
Console.WriteLine(type2);
  1. 通过类名+Type.GetType()获取,类名包含名称空间
Type type3 = Type.GetType("System.Int32");
Console.WriteLine(type3);

输出

在这里插入图片描述

2.2 获取程序集信息

Console.WriteLine(type1.Assembly);
Console.WriteLine(type2.Assembly);
Console.WriteLine(type3.Assembly);

输出

在这里插入图片描述

2.3 利用反射创建和使用对象

2.3.1 获取类中所有的公共成员
Type myType = Type.GetType("LearnReflection.Student");
MemberInfo[] infos = myType.GetMembers();
for(int i = 0; i < infos.Length; i++)
{
    Console.WriteLine(infos[i]);
}
class Student
{
    public string name;
    public int Age { get; private set; }

    private int score;


    public Student(string nmae, int age, int score) : this(nmae, age)
    {
        this.score = score;
    }

    public Student(string name, int age)
    {
        this.name = name;
        Age = age;
    }

    public Student() { }

    public void PrintInfo()
    {
        Console.WriteLine($"Name: {name}");
        Console.WriteLine($"Age: {Age}");
        PrintScore();
    }

    private void PrintScore()
    {
        Console.WriteLine($"Score:{score}");
    }

}
  • 输出包括Objec类中非静态公共方法、公共成员变量、公共成员方法、构造函数、公共属性中的公共方法、公共属性
  • 因为子类继承Object类不会继承它的静态方法

在这里插入图片描述

2.3.2 获取类的公共构造函数并调用

获取类的所有公共构造函数

ConstructorInfo[] ctors = myType.GetConstructors();
for(int i = 0;i < ctors.Length; i++)
{
    Console.WriteLine(ctors[i]);
}

输出

在这里插入图片描述

获得指定构造函数,需要传入一个类型数组与构造函数参数列表进行匹配

获取无参构造并执行

ConstructorInfo ctor1 = myType.GetConstructor(new Type[0]);
Student student1 = ctor1.Invoke(null) as Student;
Console.WriteLine(student1.Age);    //0

输出

在这里插入图片描述

获取有参构造并执行

ConstructorInfo ctor2 = myType.GetConstructor(new Type[] { typeof(string), typeof(int), typeof(int)});
Student student2 = ctor2.Invoke(new object[] { "张飞", 18, 100 }) as Student;
Console.WriteLine(student2.name);

输出

在这里插入图片描述

2.3.3 获取类的公共成员变量

获取所有公共成员变量

FieldInfo[] fieldInfos = myType.GetFields();
for(int i = 0;i<fieldInfos.Length;i++) 
{
    Console.WriteLine(fieldInfos[i]);
}

输出

在这里插入图片描述

获取指定名称的公共成员变量

FieldInfo fieldInfo = myType.GetField("name");
Console.WriteLine(fieldInfo);

输出

在这里插入图片描述

2.3.4 通过反射获取和设置对象的值

通过反射获取对象的值

Student student3 = new Student("关羽",20,600);
Console.WriteLine(fieldInfo.GetValue(student3));

输出

在这里插入图片描述

通过反射获取和设置对象的值

fieldInfo.SetValue(student3, "刘备");
Console.WriteLine(fieldInfo.GetValue(student3));

输出

在这里插入图片描述

2.3.5 通过反射获取类的公共成员方法

获取所有公共成员方法

MethodInfo[] methodInfos = myType.GetMethods();
for(int i = 0; i < methodInfos.Length; i++)
{
    Console.WriteLine(methodInfos[i]);
}

输出:不包含私有方法和protected方法

在这里插入图片描述

通过反射获取并执行指定名称的方法

MethodInfo methodInfo = myType.GetMethod("PrintInfo");
methodInfo.Invoke(student3, new object[0]);

输出

在这里插入图片描述


3、反射关键类Activator

  • 用于快速实例化对象

无参构造

Student student4 = Activator.CreateInstance(typeof(Student)) as Student;

有参构造

Student student5 = Activator.CreateInstance(typeof(Student), "曹操", 25, 1000) as Student;
student5.PrintInfo();

输出

在这里插入图片描述


4、反射关键类Assembly

  • 用来加载程序集

三种加载程序集的方式

4.1 加载同一文件夹下的其他程序集

Assembly assembly = Assembly.Load("程序集名称");

4.2 加载不同文件夹下的其他程序集

4.2.1 LoadFile
  • 加载到"无上下文"(LoadNeither)
  • 程序集被独立加载,与其他上下文隔离
Assembly assembly2 = Assembly.LoadFile("目标程序集的完全限定路径");
4.2.2 LoadFrom
  • 使用特殊的"LoadFrom"上下文
  • 程序集可以被其他需要相同程序集的代码共享
Assembly assembly3 = Assembly.LoadFrom("目标程序集的完全限定路径");

4.3 加载程序集示例

新建类库

在这里插入图片描述

编写自定义类

namespace TestReflecttionClassLib
{
    public class Point
    {
        public int x;
        public int y;
        public Point(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
    }
}

右键项目,编译生成.dll程序集

在这里插入图片描述

加载程序集,获取和使用Type对象

Assembly assembly = Assembly.LoadFrom(@"E:\ViusualStudio2022_Workplace\解决方案_练习\TestReflecttionClassLib\bin\Debug\net8.0\TestReflecttionClassLib.dll");

Type[] types = assembly.GetTypes();
for(int i = 0; i<types.Length; i++)
{
    Console.Write(types[i]);
}
//通过名称获取指定类的元信息
Type type = assembly.GetType("TestReflecttionClassLib.Point");
MemberInfo[] memberInfos = type.GetMembers();
for(int i = 0;i<memberInfos.Length; i++)
{
    Console.WriteLine(memberInfos[i]);
}

输出

在这里插入图片描述


5、完整代码示例:

源文件1

using System.Reflection;

namespace LearnReflection
{
    class Student
    {
        public string name;
        public int Age { get; private set; }

        private int score;


        public Student(string nmae, int age, int score) : this(nmae, age)
        {
            this.score = score;
        }

        public Student(string name, int age)
        {
            this.name = name;
            Age = age;
        }

        public Student() { }

        public void PrintInfo()
        {
            Console.WriteLine($"Name: {name}");
            Console.WriteLine($"Age: {Age}");
            PrintScore();
        }

        private void PrintScore()
        {
            Console.WriteLine($"Score:{score}");
        }

    }
    internal class Program
    {
        

        static void Main(string[] args)
        {
            //Type类(类的信息类):获取指定类的元数据
            //获取Type
            //1.Object类中的GetType()方法
            int a = 10;
            Type type1 = a.GetType();
            Console.WriteLine(type1);
            //2.通过类名+typeof方法
            //这种方法需要类名,而且这个类能够访问到
            Type type2 = typeof(int);
            Console.WriteLine(type2);
            //3.通过类名+Type.GetType()获取,类名包含名称空间
            Type type3 = Type.GetType("System.Int32");
            Console.WriteLine(type3);

            //获取程序集信息
            Console.WriteLine(type1.Assembly);
            Console.WriteLine(type2.Assembly);
            Console.WriteLine(type3.Assembly);

            //利用反射创建和使用对象
            //获取类中所有的公共成员
            Type myType = Type.GetType("LearnReflection.Student");
            MemberInfo[] infos = myType.GetMembers();
            for(int i = 0; i < infos.Length; i++)
            {
                Console.WriteLine(infos[i]);
            }
            //包括Objec类中非静态公共方法、公共成员变量、公共成员方法、构造函数、公共属性中的公共方法
            //因为子类继承Object类不会继承它的静态方法
            //获取类的公共构造函数并调用
            ConstructorInfo[] ctors = myType.GetConstructors();
            for(int i = 0;i < ctors.Length; i++)
            {
                Console.WriteLine(ctors[i]);
            }
            //获得指定构造函数,需要传入一个类型数组与构造函数参数列表进行匹配
            //获取无参构造并执行
            ConstructorInfo ctor1 = myType.GetConstructor(new Type[0]);
            Student student1 = ctor1.Invoke(null) as Student;
            Console.WriteLine(student1.Age);    //0
            //获取有参构造并执行
            ConstructorInfo ctor2 = myType.GetConstructor(new Type[] { typeof(string), typeof(int), typeof(int)});
            Student student2 = ctor2.Invoke(new object[] { "张飞", 18, 100 }) as Student;
            Console.WriteLine(student2.name);
            //获取类的公共成员变量
            //获取所有公共成员变量
            FieldInfo[] fieldInfos = myType.GetFields();
            for(int i = 0;i<fieldInfos.Length;i++) 
            {
                Console.WriteLine(fieldInfos[i]);
            }
            //获取指定名称的公共成员变量
            FieldInfo fieldInfo = myType.GetField("name");
            Console.WriteLine(fieldInfo);
            //通过反射获取和设置对象的值
            Student student3 = new Student("关羽",20,600);
            //获取
            Console.WriteLine(fieldInfo.GetValue(student3));
            //设置
            fieldInfo.SetValue(student3, "刘备");
            Console.WriteLine(fieldInfo.GetValue(student3));
            //通过反射获取类的公共成员方法
            MethodInfo[] methodInfos = myType.GetMethods();
            for(int i = 0; i < methodInfos.Length; i++)
            {
                Console.WriteLine(methodInfos[i]);
            }
            //通过反射获取指定名称的方法
            MethodInfo methodInfo = myType.GetMethod("PrintInfo");
            //执行方法
            methodInfo.Invoke(student3, new object[0]);

            //反射关键类Activator
            Student student4 = Activator.CreateInstance(typeof(Student)) as Student;
            //有参构造
            Student student5 = Activator.CreateInstance(typeof(Student), "曹操", 25, 1000) as Student;
            student5.PrintInfo();

            //反射关键类Assembl

            Assembly assembly = Assembly.LoadFrom(@"E:\ViusualStudio2022_Workplace\解决方案_练习\TestReflecttionClassLib\bin\Debug\net8.0\TestReflecttionClassLib.dll");
            
            Type[] types = assembly.GetTypes();
            for(int i = 0; i<types.Length; i++)
            {
                Console.Write(types[i]);
            }
            //通过名称获取指定类的元信息
            Type type = assembly.GetType("TestReflecttionClassLib.Point");
            MemberInfo[] memberInfos = type.GetMembers();
            for(int i = 0;i<memberInfos.Length; i++)
            {
                Console.WriteLine(memberInfos[i]);
            }

        }

    }
}

源文件2

namespace TestReflecttionClassLib
{
    public class Point
    {
        public int x;
        public int y;
        public Point(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
    }
}

6、参考资料

  1. 《唐老狮C#》

本文结束,感谢您的阅读~

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值