C#反射

首先我们可以先来了解下什么是反射

        Reflection,中文翻译为反射。         这是.Net中获取运行时类型信息的方式,.Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型 (class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,例如:         Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。 Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。 MethodInfo包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。 诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。

程序代码在编译后生成可执行的应用,我们要了解这种可执行应用程序的结构。

  程序集包含模块,而模块包含类型,类型又包含成员。

  反射则提供了封装程序集、模块和类型的对象。

  您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。

  然后,可以调用类型的方法或访问其字段和属性。

反射通常具有以下用途:

1.使用 Assembly 定义和加载程序集,加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。

2.使用 Module 了解如下的类似信息:包含模块的程序集以及模块中的类等。您还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。

3.使用 ConstructorInfo 了解以下信息:构造函数的名称、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。使用 Type 的 GetConstructors 或 GetConstructor 方法来调用特定的构造函数。

4.使用 MethodInfo 了解以下信息:方法的名称、返回类型、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。使用 Type 的 GetMethods 或 GetMethod 方法来调用特定的方法。

5.使用 FieldInfo 了解以下信息:字段的名称、访问修饰符(如 public 或 private)和实现详细信息(如 static)等;并获取或设置字段值。

6.使用 EventInfo 来了解如下的类似信息:事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。

7.使用 EventInfo 来了解如下的类似信息:事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。

8.使用 ParameterInfo 来了解如下的类似信息:参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等。

9.当您在一个应用程序域的仅反射上下文中工作时,请使用 CustomAttributeData 来了解有关自定义属性的信息。使用 CustomAttributeData,您不必创建属性的实例就可以检查它们。

下面我们通过实例代码来看一下:

    public class Person
    {
        public string Name;
        private int _Age;
        public int Age
        {
            get
            {
                return _Age;
            }
            set
            {
                _Age = value;
            }
        }
        public Person(string Name)
        {
            this.Name = Name;
        }
        public void DisplayInfo(string info)
        {
            System.Console.WriteLine(info);
            System.Console.WriteLine("called sucessfully!");
        }
        public void DisplayName()
        {
            System.Console.WriteLine(Name);
        }
        public string getName()
        {
            return Name;
        }
    }

首先我创建了一个控制台的应用程序,然后定义一个实体Person类。

接下来就来看看Main函数中的实现代码吧。

        static void Main(string[] args)
        {
            //从Dll中加载
            //Assembly ass = Assembly.LoadFile(@"TestReflect.dll");
            //Type myType = ass.GetType("testReflection.Person");
            //object aPerson = ass.CreateInstance("Person");

            //取得类型
            Type myType = Type.GetType("testReflection.Person");
            //构造函数要用到的参数
            object[] constuctParms = new object[] { "Brad Pitt" };
            //创建实例
            //object TestName = Assembly.GetAssembly(myType).CreateInstance("Person"); 
            object aPerson = Activator.CreateInstance(myType, constuctParms);

            //使用MethodInfo 和Invoke 调用方法
            MethodInfo displayInfoMethod = myType.GetMethod("DisplayInfo");
            displayInfoMethod.Invoke(aPerson, new object[] { "Using Invoke to call Method DisplayInfo()" });

            //使用InvokeMember 调用方法
            //调用方法的一些标志位
            BindingFlags flag = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance;
            myType.InvokeMember("DisplayInfo", flag, null, aPerson, new object[] { "Using InvokeMethod to call DisplayInfo()" });
            //如果方法有返回值
            string name = (string)myType.InvokeMember("getName", flag, null, aPerson, null);
            System.Console.WriteLine("call getName(), return: " + name);

            //设置属性值
            myType.InvokeMember("Age", BindingFlags.SetProperty, null, aPerson, new object[] { 30 });
            //得到属性值
            int age = (int)myType.InvokeMember("Age", BindingFlags.GetProperty, null, aPerson, null);
            System.Console.WriteLine("Get the property of Age : " + Convert.ToString(age));

            //设置字段值
            myType.InvokeMember("Name", BindingFlags.SetField, null, aPerson, new object[] { "Michal Jodn" });
            //获取字段值
            string fname = (string)myType.InvokeMember("Name", BindingFlags.GetField, null, aPerson, null);
            System.Console.WriteLine("Get the Field Value of Name : " + fname);

            myType.InvokeMember("DisplayName", flag, null, aPerson, null);

            //获得方法集
            MethodInfo[] methods = myType.GetMethods();
            foreach (MethodInfo m in methods)
            {
                System.Console.WriteLine(m.Name);
            }
            //同样还有:GetFiedls()、GetProperties()、GetEvents()等方法

            //使用Delegate
            //此方法是静态的,所以必须提供委托类型。
            TestDelegate dg = (TestDelegate)Delegate.CreateDelegate(typeof(testReflection.TestDelegate), aPerson, "DisplayInfo");
            dg("Test Delegate by call DisplayInfo()");


            //获得解决方案的所有Assembly
            Assembly[] AX = AppDomain.CurrentDomain.GetAssemblies();
            //遍历显示每个Assembly的名字
            foreach (object var in AX)
            {
                Console.WriteLine("Assembly的名字:" + var.ToString());
            }
            //使用一个已知的Assembly名称,来创建一个Assembly
            //通过CodeBase属性显示最初指定的程序集的位置
            Console.WriteLine("最初指定的程序集TestReflection的位置:" + Assembly.Load("TestReflection").CodeBase);
            System.Console.ReadLine();
        }

 说明:

您也可以直接下载代码进行调试查看 示例代码 使用反射动态调用类成员,需要Type类的一个方法:InvokeMember。对该方法的声明如下:

public object InvokeMember(    string name,    BindingFlags invokeAttr,    Binder binder,    object target,    object[] args );

参数

name String,它包含要调用的构造函数、方法、属性或字段成员的名称。 - 或 - 空字符串 (""),表示调用默认成员。

invokeAttr 一个位屏蔽,由一个或多个指定搜索执行方式的 BindingFlags 组成。访问可以是 BindingFlags 之一,如 Public、NonPublic、Private、InvokeMethod 和 GetField 等。不需要指定查找类型。如果省略查找类型,则将应用 BindingFlags.Public | BindingFlags.Instance。

binder 一个 Binder 对象,该对象定义一组属性并启用绑定,而绑定可能涉及选择重载方法、强制参数类型和通过反射调用成员。 - 或 - 若为空引用(Visual Basic 中为 Nothing),则使用 DefaultBinder。

target 在其上调用指定成员的 Object。

args 包含传递给要调用的成员的参数的数组。

返回值 表示被调用成员的返回值的 Object。

下列 BindingFlags 筛选标志可用于定义包含在搜索中的成员:

为了获取返回值,必须指定 BindingFlags.Instance 或 BindingFlags.Static。 指定 BindingFlags.Public 可在搜索中包含公共成员。 指定 BindingFlags.NonPublic 可在搜索中包含非公共成员(即私有成员和受保护的成员)。 指定 BindingFlags.FlattenHierarchy 可包含层次结构上的静态成员。

下列 BindingFlags 修饰符标志可用于更改搜索的执行方式: BindingFlags.IgnoreCase,表示忽略 name 的大小写。 BindingFlags.DeclaredOnly,仅搜索 Type 上声明的成员,而不搜索被简单继承的成员。

可以使用下列 BindingFlags 调用标志表示要对成员采取的操作: CreateInstance,表示调用构造函数。忽略 name。对其他调用标志无效。 InvokeMethod,表示调用方法,而不调用构造函数或类型初始值设定项。 对 SetField 或 SetProperty 无效。 GetField,表示获取字段值。对 SetField 无效。 SetField,表示设置字段值。对 GetField 无效。 GetProperty,表示获取属性。对 SetProperty 无效。 SetProperty 表示设置属性。对 GetProperty 无效。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 系统架构师-基础到企业应用架构-分层[上篇]

          大家好,接近一年的时间没有怎么书写博客了,一方面是工作上比较忙,同时生活上也步入正轨,事情比较繁多,目前总算是趋于稳定,可以有时间来完善以前没有写完...

    aehyok
  • ExtJs二(实现登录)

      在上一次http://www.cnblogs.com/aehyok/archive/2013/04/17/3025957.html主要是搭建Ext环境,本次...

    aehyok
  • Knockout.Js官网学习(text绑定)

    text 绑定到DOM元素上,使得该元素显示的文本值为你绑定的参数。该绑定在显示<span>或者<em>上非常有用,但是你可以用在任何元素上。

    aehyok
  • 产品运营之我见

    在运营之初,需先明确运营的整体战略,可分为品牌、产品、生态。企业的不同阶段,对于各点也侧重不同。后续的运营工作,需按照不同侧重,有所针对性的安排。

    用户5548425
  • 从香农熵到手推KL散度:一文带你纵览机器学习中的信息论

    IT派 - {技术青年圈} 持续关注互联网、大数据、人工智能领域 信息论是应用数学的一个分支,主要研究的是对一个信号包含信息的多少进行量化。它最初被发明是用来...

    IT派
  • 从香农熵到手推KL散度:一文带你纵览机器学习中的信息论

    机器之心
  • DjangoRestFramework,restful规范、APIview、解析器组件、Postman等

      大家还记得CBV的这个视图函数,为什么get请求就能找到类的get方法,post请求就能找到post方法,其内部有个dispatch方法来进行分发,这又怎么...

    changxin7
  • storm togolopy转换jstorm topology

    本文参照https://my.oschina.net/shyloveliyi/blog/785812中代码,进行转换。

    尚浩宇
  • 【聚焦】在寒冷的天气里 谈谈大数据如何提高天气预报的准确性

    天气预报是大数据应用最早的领域之一, 古人们总结出的节气和天气谚语沿用了几个世纪。 ? 如何预测天气 前650年左右巴比伦人使用云的样子来预测天气。中国人至少在...

    小莹莹
  • 在探索中前行---浅谈腾讯数据中心运营文化实践

    导语:倘若数据中心,有了完整的运营体系,有了统一的方法论,有了专业的运营团队,有了先进的运营工具,是不是能长治久安了呢?答案显然是不够的。如果我们在数据中心运营...

    腾讯数据中心

扫码关注云+社区

领取腾讯云代金券