C#反射(Reflection)

反射(Reflection)是指程序可以访问、检测和修改它本身状态或行为的一种能力,反射中提供了用来描述程序集、模块和类型的对象,可以使用反射动态地创建类型的实例,并将类型绑定到现有对象,或者从现有对象中获取类型,然后调用其方法或访问其字段和属性。 如果代码中使用了特性,也可以利用反射来访问它们。

反射的用途

C# 中反射具有以下用途:
  • 在运行时查看视图属性信息;
  • 检查装配中的各种类型并实例化这些类型;
  • 在后期绑定到方法和属性;
  • 在运行时创建新类型,然后使用这些类型执行一些任务。

查看元数据

前面我们提到了可以使用反射查看特性的信息,下面就来看一下具体的操作步骤。首先需要初始化 System.Reflection 类的 MemberInfo 对象,用来发现与类关联的属性,例如:

System.Reflection.MemberInfo info = typeof(MyClass);

完整的示例代码如下所示:
using System;

[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute {
    public readonly string Url;
  
    public string Topic   // Topic 是一个 name_parameter
    {
        get {
            return topic;
        }
        set {
            topic = value;
        }
    }
    public HelpAttribute(string url)   // url 是一个 positional_parameters
    {
        this.Url = url;
    }
    private string topic;
}

[HelpAttribute("关于 MyClass 的信息")]
class MyClass {

}

namespace c.biancheng.net
{
    class Demo
    {
        static void Main(string[] args) 
        {
            System.Reflection.MemberInfo info = typeof(MyClass);
            object[] attributes = info.GetCustomAttributes(true);
        
            for (int i = 0; i < attributes.Length; i++) {
                System.Console.WriteLine(attributes[i]);
            }
            Console.ReadKey();
        }
    }
}
运行结果如下:

HelpAttribute

【示例】在本例中,我们将使用在上一节中创建的 DeBugInfo 特性,并使用反射(Reflection)来读取矩形类中的元数据。
using System;
using System.Reflection;

namespace c.biancheng.net
{
    // 要分配给类及其成员的自定义属性错误修复程序
    [AttributeUsage(
    AttributeTargets.Class |
    AttributeTargets.Constructor |
    AttributeTargets.Field |
    AttributeTargets.Method |
    AttributeTargets.Property,
    AllowMultiple = true)]

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

        public DeBugInfo(int bg, string dev, string d) {
            this.bugNo = bg;
            this.developer = dev;
            this.lastReview = d;
        }
        public int BugNo {
            get {
                return bugNo;
            }
        }
        public string Developer {
            get {
                return developer;
            }
        }
        public string LastReview {
            get {
                return lastReview;
            }
        }
        public string Message {
            get {
                return message;
            }
            set {
                message = value;
            }
        }
    }
    [DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "返回值类型不匹配")]
    [DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "变量未使用")]

    class Rectangle {
        // 成员变量
        protected double length;
        protected double width;

        public Rectangle(double l, double w) {
            length = l;
            width = w;
        }
        [DeBugInfo(55, "Zara Ali", "19/10/2012", Message = "返回值类型不匹配")]
        public double GetArea() {
            return length * width;
        }
        [DeBugInfo(56, "Zara Ali", "19/10/2012")]
        public void Display() {
            Console.WriteLine("长: {0}", length);
            Console.WriteLine("宽: {0}", width);
            Console.WriteLine("面积: {0}", GetArea());
        }
    }

    class Demo
    {
        static void Main(string[] args) 
        {
            Rectangle r = new Rectangle(4.5, 7.5);
            r.Display();
            Type type = typeof(Rectangle);

            // 遍历 Rectangle 类的属性
            foreach (Object attributes in type.GetCustomAttributes(false)) {
                DeBugInfo dbi = (DeBugInfo)attributes;

                if (null != dbi) {
                    Console.WriteLine("Bug 编号: {0}", dbi.BugNo);
                    Console.WriteLine("开发者: {0}", dbi.Developer);
                    Console.WriteLine("上次审核时间: {0}", dbi.LastReview);
                    Console.WriteLine("评论: {0}", dbi.Message);
                }
            }

            // 遍历函数属性
            foreach (MethodInfo m in type.GetMethods()) {
                foreach (Attribute a in m.GetCustomAttributes(true)) {
                    DeBugInfo dbi = (DeBugInfo)a;

                    if (null != dbi) {
                        Console.WriteLine("Bug 编号: {0}, 函数名: {1}", dbi.BugNo, m.Name);
                        Console.WriteLine("开发者: {0}", dbi.Developer);
                        Console.WriteLine("上次审核时间: {0}", dbi.LastReview);
                        Console.WriteLine("评论: {0}", dbi.Message);
                    }
                }
            }
            Console.ReadLine();
        }
    }
}
运行结果如下:

长: 4.5
宽: 7.5
面积: 33.75
Bug 编号: 49
开发者: Nuha Ali
上次审核时间: 10/10/2012
评论: 变量未使用
Bug 编号: 45
开发者: Zara Ali
上次审核时间: 12/8/2012
评论: 返回值类型不匹配
Bug 编号: 55, 函数名: GetArea
开发者: Zara Ali
上次审核时间: 19/10/2012
评论: 返回值类型不匹配
Bug 编号: 56, 函数名: Display
开发者: Zara Ali
上次审核时间: 19/10/2012
评论: