天天看点

【反射】C#:反射(Reflection)

一、定义

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

程序包含模块、类型、成员,反射提供的是封装程序集、模块、类型、成员的对象。

二、作用

可以动态创建类型的实例,将类型绑定到现有对象;或者从现有对象中获取类型。然后,可以调用类型的方法或者访问其字段和属性。

三、使用

1.用途

  • 它允许在运行时查看特性(attribute)信息
  • 它允许审查集合中的各种类型,以及实例化这些类型
  • 它允许延迟绑定的方法和属性(property)
  • 它允许在运行时创建新类型,然后使用这些类型执行一些任务

2.命名空间

using System.Reflection;
using System.Type;
using System.Reflection.Assembly;
           

常用的为Type和Assembly两个类。

3.属性与方法

Type类
属性 说明
Name 数据类型名
FullName 获取该类型的完全限定名称,包括其命名空间,但不包括程序集。
Namespace 定义数据类型的命名空间名
Attribute 获取与 Type 关联的属性
CustomAttributes 获取包含此成员自定义属性的集合。(继承自 MemberInfo)
方法 说明
GetConstructors() 返回ConstructorInfo类型数组,获取当前Type定义的所有公共构造函数
GetEvent(),GetEvents() 返回EventInfo类型,获取该Type的事件信息
GetField(), GetFields() 返回FieldInfo类型,获取该Type的字段(成员变量)的信息
GetInterface(), GetInterfaces() 返回InterfaceInfo类型,获取该Type实现的接口的信息
GetMember(), GetMembers() 返回MemberInfo类型,获取该Type的所有成员的信息
GetMethod(),GetMethods() 返回MethodInfo类型,获取该Type的方法的信息
GetProperty(), GetProperties() 返回PropertyInfo类型,获取该Type的属性的信息
GetEnumNames() 返回当前枚举类型中各个成员的名称

更多请到Type官方文档…

Assembly类

Assembly类可以获取正在执行的程序集;可以动态加载程序集;以及在程序集中查找并创建类型实例。

使用:

//通过程序集名称返回Assembly对象
Assembly assembly = Assembly.Load("AssemblyName");
//通过dll文件名称返回Assembly对象
Assembly assembly = Assembly.LoadFrom("*.dll");
//通过Assembly对象获取具体类
Type t = assembly.GetType("ClassName");   //参数必须是全名
           

更多到 Assembly官方文档…

四、实例

using System;
using System.Reflection;

namespace ReflectionTest
{
    class Student
    {
        public Student() { }

        public Student(string name)
        {
            this.name = name;
        }

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

        private string name;

        private int age;

        public string Name { get { return name; } set { name = value; } }

        public int Age { get { return age; } set { age = value; } }

        public void Show()
        {
            Console.WriteLine("name:{0},age{1}", this.name, this.age);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {

            Assembly assembly = Assembly.Load("ReflectionTest");        // 加载程序集

            Type t = assembly.GetType("ReflectionTest.Student");                       // 加载类

            // 1. 查看类中的构造方法与参数
            ConstructorInfo[] ciArr = t.GetConstructors();              // 获取类的所有构造函数
            foreach (var ci in ciArr)
            {
                ParameterInfo[] paras = ci.GetParameters();             // 循环每个构造函数获取并打印参数
                foreach (var para in paras)
                {
                    Console.WriteLine(para.ParameterType.ToString() + "\n" + para.Name);
                }
            }

            // 2. 查看类中的属性
            PropertyInfo[] pis = t.GetProperties();
            foreach (var pi in pis)
            {
                Console.WriteLine(pi.Name + "\n");
            }

            // 3. 用构造函数生成对象
            Type[] types = new Type[pis.Length];
            for (int i = 0; i < pis.Length; i++)
            {
                types[i] = pis[i].PropertyType;
            }
            ConstructorInfo ci0 = t.GetConstructor(types);
            object[] o = new object[] { "盖伦", 22 };
            object obj = ci0.Invoke(o);

            ((Student)obj).Show();

            // 4. 用Activator生成对象
            object[] o2 = new object[] { "亚索", 23 };
            object obj2 = Activator.CreateInstance(t, o2);
            ((Student)obj2).Show();

            // 5. 查看类中的方法(所有公共方法)
            foreach (var mi in t.GetMethods())
            {
                Console.WriteLine(mi.Name + "");
            }

            // 6. 取得类中的方法并执行
            object o3 = Activator.CreateInstance(t);             // 创建一个类的实例
            PropertyInfo nameF = t.GetProperty("Name");         // 获取Name属性
            nameF.SetValue(o3, "瑞文");
            PropertyInfo ageF = t.GetProperty("Age");           // 获取Age属性
            ageF.SetValue(o3, 18);

            MethodInfo methodInfo = t.GetMethod("Show");

            methodInfo.Invoke(o3, null);

            Console.ReadKey();

        }
    }
}
           

执行结果:

【反射】C#:反射(Reflection)

五、总结

  • 优点

反射提高了程序的灵活性和拓展性;降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需提供硬编码目标类。

  • 缺点

1、性能问题:使用反射基本上是一种解释操作,包括了一些动态的类型,用于字段和方法接入时要远慢于直接代码,因此反射操作的效率要比非反射操作慢很多。

2、使用反射会模糊程序内内部逻辑:程序员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂