C# 反射(Reflection)

什么是反射

发射是 .net framework 提供的一个帮助类库,用于读取和使用元数据。

用到的类:System.Reflection,System.Type。System.Type 类对于反射起着核心的作用。 当反射请求加载的类型时,公共语言运行时将为它创建一个 Type。 您可以使用 Type 对象的方法、字段、属性和嵌套类来查找有关该类型的所有信息。

反射优缺点

优点:

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

缺点:

  • 1、性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
  • 2、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。

反射的用途

  • 1、它允许在运行时查看特性(attribute)信息。
  • 2、它允许审查集合中的各种类型,以及实例化这些类型。
  • 3、它允许延迟绑定的方法和属性(property)。
  • 4、它允许在运行时创建新类型,然后使用这些类型执行一些任务。
  • 5、MVC的路由就是反射做的。访问的Global的时候,会加载一遍dll

查看元数据

1、获取当前实例的 System.Type 的两种方式

//使用对象 GetType()方法
Rectangle nc = new Rectangle();
Type type = nc.GetType();
            
//使用 C# typeof 运算符
Type type = typeof(Rectangle);

2、查看类中的成员

MemberInfo[] minfos = type.GetMembers();
foreach (var i in minfos)
{
    Console.WriteLine("成员: {0}", i.Name);
}

3、查看类中的构造方法

ConstructorInfo[] ci = type.GetConstructors();
foreach (var i in ci)
{
    Console.WriteLine("构造函数: {0}", i.Name);
}

4、查看类中的属性

PropertyInfo[] pis = type.GetProperties();
foreach (var i in pis)
{
    Console.WriteLine("属性: {0}", i.Name);
}

5、查看类中的字段

FieldInfo[] fis = type.GetFields();
foreach (var i in fis)
{
    Console.WriteLine("字段: {0}", i.Name);
}

6、用反射生成对象,并调用属性、方法和字段进行操作

object obj = Activator.CreateInstance(type);// 创建实例
FieldInfo fi = type.GetField("hight");// 取得hight字段 
fi.SetValue(obj, 5);// 给hight字段赋值 
PropertyInfo pi1 = type.GetProperty("length");// 取得length属性 
pi1.SetValue(obj, 10, null);// 给length属性赋值
PropertyInfo pi2 = type.GetProperty("width");// 取得width属性 
pi2.SetValue(obj, 20, null);// 给width属性赋值 
MethodInfo mi = type.GetMethod("GetVolume");// 取得GetVolume方法 
mi.Invoke(obj, null);// 调用GetVolume方法

7、查看类中的特性、

Object[] attributes = type.GetCustomAttributes(false);
foreach (var i in attributes)
{
    DeBugInfo dbi = i as DeBugInfo;
    if (null != dbi)
    {
        Console.WriteLine("Bug no: {0}, Message: {1}", dbi.BugNo, dbi.Message);
    }
}

8、完整代码

using System;
using System.Reflection;
namespace ConsoleTest
{
    // 一个自定义特性 BugFix 被赋给类及其成员
    [AttributeUsage(AttributeTargets.Class |
    AttributeTargets.Constructor |
    AttributeTargets.Field |
    AttributeTargets.Method |
    AttributeTargets.Property,
    AllowMultiple = true)]

    public class DeBugInfo : System.Attribute
    {
        private int bugNo;
        public string message;

        public DeBugInfo(int bg)
        {
            this.bugNo = bg;
        }

        public int BugNo
        {
            get
            {
                return bugNo;
            }
        }
        public string Message
        {
            get
            {
                return message;
            }
            set
            {
                message = value;
            }
        }
    }
    /// <summary>
    /// 矩形
    /// </summary>
    [DeBugInfo(45, Message = "Return type mismatch")]
    [DeBugInfo(49, Message = "Unused variable")]
    public class Rectangle
    {
        public int hight = 0;
        public double length { get; set; }
        public double width { get; set; }
        public Rectangle()
        {
        }
        public Rectangle(double l, double w)
        {
            length = l;
            width = w;
        }
        // 计算面积
        [DeBugInfo(55, Message = "Return type mismatch")]
        public void GetArea()
        {
            Console.WriteLine("面积: {0}", length * width);
        }
        //计算体积
        [DeBugInfo(56)]
        public void GetVolume()
        {
            Console.WriteLine("体积: {0}", length * width * hight);
        }
    }

    class ExecuteRectangle
    {
        public static void Main12()
        {
            //使用对象GetType()方法
            //Rectangle nc = new Rectangle();
            //Type type = nc.GetType();
            
            //使用 C# typeof 运算符
            Type type = typeof(Rectangle);

            // 获取 Rectangle 类的所有成员
            Console.WriteLine("\n遍历 Rectangle 类的成员开始---------------");
            MemberInfo[] minfos = type.GetMembers();
            foreach (var i in minfos)
            {
                Console.WriteLine("成员: {0}", i.Name);
            }
            Console.WriteLine("-------------------结束-------------------");

            // 获取 Rectangle 类的所有构造函数
            Console.WriteLine("\n遍历 Rectangle 类的构造函数开始-----------");
            ConstructorInfo[] ci = type.GetConstructors();
            foreach (var i in ci)
            {
                Console.WriteLine("构造函数: {0}", i.Name);
            }
            Console.WriteLine("-------------------结束-------------------");

            // 获取 Rectangle 类的所有属性
            Console.WriteLine("\n遍历 Rectangle 类的属性开始---------------");
            PropertyInfo[] pis = type.GetProperties();
            foreach (var i in pis)
            {
                Console.WriteLine("属性: {0}", i.Name);
            }
            Console.WriteLine("-------------------结束-------------------");

            // 获取 Rectangle 类的所有public字段
            Console.WriteLine("\n遍历 Rectangle 类的字段开始---------------");
            FieldInfo[] fis = type.GetFields();
            foreach (var i in fis)
            {
                Console.WriteLine("字段: {0}", i.Name);
            }
            Console.WriteLine("-------------------结束-------------------");

            //用反射生成对象,并调用属性、方法和字段进行操作
            Console.WriteLine("\n用反射生成对象,并调用属性、方法和字段进行操作");
            object obj = Activator.CreateInstance(type);// 创建实例
            FieldInfo fi = type.GetField("hight");// 取得hight字段 
            fi.SetValue(obj, 5);// 给hight字段赋值 
            PropertyInfo pi1 = type.GetProperty("length");// 取得length属性 
            pi1.SetValue(obj, 10, null);// 给length属性赋值
            PropertyInfo pi2 = type.GetProperty("width");// 取得width属性 
            pi2.SetValue(obj, 20, null);// 给width属性赋值 
            MethodInfo mi = type.GetMethod("GetVolume");// 取得GetVolume方法 
            mi.Invoke(obj, null);// 调用GetVolume方法
            Console.WriteLine("-------------------结束-------------------");

            // 遍历 Rectangle 类的特性
            Console.WriteLine("\n遍历 Rectangle 类的特性开始---------------");
            Object[] attributes = type.GetCustomAttributes(false);
            foreach (var i in attributes)
            {
                DeBugInfo dbi = i as DeBugInfo;
                if (null != dbi)
                {
                    Console.WriteLine("Bug no: {0}, Message: {1}", dbi.BugNo, dbi.Message);
                }
            }
            Console.WriteLine("-------------------结束-------------------");

            // 遍历 Rectangle 类的方法上的特性(此处只遍历)
            Console.WriteLine("\n遍历 Rectangle 类的方法上的特性开始-------");
            MethodInfo[] m = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            foreach (var i in m )
            {
                foreach (Attribute a in i.GetCustomAttributes(true))
                {
                    DeBugInfo dbi = a as DeBugInfo;
                    if (null != dbi)
                    {
                        Console.WriteLine("Bug no: {0}, for Method: {1}, Message: {2}", dbi.BugNo, i.Name, dbi.Message);
                    }
                }
            }
            Console.WriteLine("-------------------结束-------------------");

            Console.ReadLine();
        }
    }
}

反射的完整代码
反射的完整代码

运行结果:

System.Reflection.Assembly类

Assembly类可以获得程序集的信息,也可以动态的加载程序集,以及在程序集中查找类型信息,并创建该类型的实例。

使用Assembly类可以降低程序集之间的耦合,有利于软件结构的合理化。

//通过程序集名称返回Assembly对象
Assembly ass = Assembly.Load("ConsoleTest");

//通过DLL、EXE文件名称返回Assembly对象
Assembly ass = Assembly.LoadFrom("ConsoleTest.exe");

//通过Assembly获取程序集中类
Type t = ass.GetType("ConsoleTest.Rectangle");   //参数必须是类的全名

//通过Assembly获取程序集中所有的类
Type[] types = ass.GetTypes();

 

 


相关文章:http://www.runoob.com/csharp/csharp-reflection.html  

              https://www.cnblogs.com/Kare/p/4601436.html  

              http://www.cnblogs.com/yaozhenfa/p/CSharp_Reflection_1.html#3826975

 

posted @ 2018-02-17 21:16    阅读(948)  评论(0编辑  收藏  举报