zoukankan      html  css  js  c++  java
  • 反射使用基础

    1. 反射技术基础   

    2. Type类   

    3. 动态对像创建与方法调用   

    1.反射技术基础

    反射(Reflection)是.NET中的一个重要技术,通过反射可以在运行时获得某个类型的各种信息,包括方法、属性、事件、以及构造函数等。还可以获得每个成员的名称、访问权限和参数等信息,由于这些信息都保存在程序集的元数据中,因此反射处理的对像是程序集元数据。利用反射技术,即可对每一个类型了如指掌。知道了类型的相关信息,就可以在程序运行时动态地创建对像,调用方法、设置属性和激发事件,所有这些都不是编译时完成的。.NET Framework甚至提供了一种方法,运行时在内存中直接无中生有的创建一个程序集(Assembly)向程序集中添加类型(type),通过ILGenerator对像直接向类型方法注入IL指令并直接执行之。

    .NET程序集的层次结构
    C#程序由一个或多个源文件组成。程序中声明类型(type),类型包含”成员”(Member)比如典型的类中就有方法,属性,字段和事件等成员,并且可按命名空间(Namespace)进行组织,类和接口就是类型的示例。在编译C#程序时,它们被打包为程序集(Assembly),
    程序集通常具有文件扩展名.exe或.dll,前者是独立的可执行程序,后者必需被加载到一个进程之后,其包含的代码才能被执行。
    每个程序集都由一个或若干个模块(Moudle)组成,模块包含IL指令与资源,但不包含程序集清单,以EXE或DLL文件的形式存在。
    绝大数情况下,一个程序集只包含一个模块,换句话说模块文件(DLL或EXE)就是程序集本身。

    NET Framework以一系列的类型来表达上述概念

    类型名 说明
    Assembly  程序集
    Module 模块
    ConstructorInfo  构造函数
    MethodInfo  方法
    FieldInfo  字段
    PropertyInfo  属性
    EventInfo  事件
    ParameterInfo  参数

    每个特定的程序集都由一个Assembly类的实例表示。Assembly类提供了一些静态方法用于得到这个对像的引用

    获取特定类型所在程序集引用:Console.WriteLine(Assembly.GetAssembly(typeof(Program)).Location);   //program是定义的一个类 也可以用:Console.WriteLine(typeof(Program)Assembly.Location);

    获取包含了当前正在执行的代码的程序集引用:Console.WriteLine(Assembly.GetExecutingAssembly().Location);

    获取入口程序集引用:入口程序集,指的是进程的默认应用程序域中首先启动的那个程序集,比如控制台应用程序中Main方法所在的那个程序集,如果是其它的应用程序域,通常是指这一应用程序域调用ExecuteAssembly方法所执行的第一个程序集。 如以下代码输出当前应用程序域中入口程序集的完整地址 Console.WriteLine(Assembly.GetEntryAssembly().Location);

    2.Type类

    Type类是一种特殊的数据类型,所有数据类型都有属于自已的特定信息。
    首先来看一段代码
        public class MyClass
        {
            public int MyField;
            public void MyMethod() { }
            public string MyProperty { get; set; }
        }
        class Program
        {
            static void Main(string[] args)
            {
                MyClass obj = new MyClass(); //创建对象
                //获取类型对象
                Type typ = obj.GetType();

                //输出类的名字
                Console.WriteLine(typ.Name);
                //判断其是否公有的
                Console.WriteLine(typ.IsPublic);
                //判断两个对象是否属于同一类型
                Console.WriteLine(IsTheSameType(obj,new MyClass()));
                Console.ReadKey();

            }
            static bool IsTheSameType(Object obj1, Object obj2)
            {
                return (obj1.GetType() == obj2.GetType());
            }
        }

    上述代码先创建了一个MyClass类型的对像,通过调用GetType方法(从Object类继承)得到一个Type类型的对像,根据此对像即可知道MyClass这一类型的类型名,是否公在等信息,判断两个对像是否属于同一类型,可以直接比对其Type对像是否为同一个,具体看IsTheSameType方法。

    创建Type对像

    通过对像创建
    .Net Framework中所有的数据类型都派生自Object类,而Object类提供了GetType方法,所以可以通过对所在的对对像调用GetType演绎法儿取其数据类型信息
    int i = 100;
    Type type = i.GetType();
    Console.WriteLine(type.Name);  //输出为int32

    通过语言关键字创建
    c#提供了一个typeof对像,可以根据数据类型直接获取对应的Type对像
    如:Type type=typeof(int);

    通过传入的参数名获取Type
    GetType有几个重载形式,
    常用的是以下这种:public static Type GetType(string name),需要注意的是传入的参数必须是完整的类型限定名,比如"System.Int32",而不是是仅为"Int32"
    代码示例:
    namespace MyNameSpace
    {
        namespace ChildSpace
        {
            public class Outer
            {
                public class Inner{ }
            }
        }
    }
    以上代码要获取outer所对应的type对像: Type type = Type.GetType("MyNameSpace.ChildSpace.Outer");
    上述代码中还有一个类Inner,所有代码都在类的内部,这种类称为内部类或嵌套类,使用+来构造内部类的类型名,
    Type type3 = Type.GetType("MyNameSpace.ChildSpace.Outer+Inner");

    获取了Type对像之后,即可使用它的各种方法来获取特定数据类型的各种信息,下面这段示例代码获取MyClass.dll中类UserInfo下的各个成员并显示到窗体上,结果如

           

    //MyClass定义如下
    namespace MyClass
    {
        public class UserInfo
        {
            string strT;
            public UserInfo()
            {
                strT = "aaa";
            }
            public UserInfo(string a, string b)
            {
                strT = a + b;
            }
            public int Add(int i)
            {
                return i;
            }
            public int Subtract(int i, int j)
            {
                return i - j;
            }
            public string Name
            {
                get;
                set;
            }
            public string Age
            {
                get;
                set;
            }
            public string Tel;
            public string Mobile;

        }
    }
          //获取MyClass.dll中UserInfo类的各个成员
            public void ReflecForClass()
            {
                Assembly assembly = Assembly.LoadFrom("MyClass.dll");
                object obj = assembly.CreateInstance("MyClass.UserInfo");
                Type type = obj.GetType();
                //构造函数
                ConstructorInfo[] cons = type.GetConstructors();
                string constructTemp = "" ;
                foreach (ConstructorInfo con in cons)
                {
                    constructTemp += con.ToString() + " ";
                }
                txtConstructor.Text = constructTemp;
                //方法
                MethodInfo[] meths = type.GetMethods();
                string methodTemp = "";
                foreach (MethodInfo meth in meths)
                {
                    methodTemp += meth.ToString() + " ";
                }
                txtMethod.Text = methodTemp;
                //属性
                PropertyInfo[] props = type.GetProperties();
                string propertyTemp = "";
                foreach (PropertyInfo prop in props)
                {
                    propertyTemp += prop.ToString() + " ";
                }
                txtProperty.Text = propertyTemp;
                //字段
                FieldInfo[] fields = type.GetFields();
                string fieldTemp = "";
                foreach (FieldInfo field in fields)
                {
                    fieldTemp += field.ToString() + " ";
                }
                txtField.Text = fieldTemp;
            }

    Type类获取类型信息的各种方法总结为:

     3.动态对像创建与方法调用

    首先看个例子,一个四则运算器,这个例子不一样的地方是基于反射开发的。

    首先会定义一个接口
    namespace InterfaceLib
    {
        public interface IMathOpt
        {
            double GetIt(double x, double y);
        }
    }
    再定义一个MathLibrary库,定义了加、减、乘、除四种运算,所有类都实现了接口库中的IMathOpt接口
    namespace MathOptLibrary
    {
        public class AddClass:IMathOpt
        {
            double IMathOpt.GetIt(double x, double y)
            {
                return x + y;
            }

        }
        public class SubstructClass : IMathOpt
        {
            double IMathOpt.GetIt(double x, double y)
            {
                return x - y;
            }
        }
        public class MultiplyClass :IMathOpt
        {
            double IMathOpt.GetIt(double x, double y)
            {
                return x * y;
            }
        }

        public class DivideClass :IMathOpt
        {
            double IMathOpt.GetIt(double x, double y)
            {
                return x / y;
            }
        }
    }
    启动项目DynamicCreatedObject引用InterfaceLib,但不需要引用MathLibrary.dll       
    private void btnResult_Click(object sender, EventArgs e)
    {
        IMathOpt mathopt;
        Assembly assembly = Assembly.LoadFrom("MathOptLibrary.dll");
        switch (cbxOpt.SelectedItem.ToString())
        {
          case "+":
            mathopt =(IMathOpt)assembly.CreateInstance("MathOptLibrary.AddClass");
            break;
          case "-":
            mathopt = (IMathOpt)assembly.CreateInstance("MathOptLibrary.SubstructClass");
            break;
          case "*":
            mathopt = (IMathOpt)assembly.CreateInstance("MathOptLibrary.MultiplyClass");
            break;
          case "/":
             mathopt = (IMathOpt)assembly.CreateInstance("MathOptLibrary.DivideClass");
             break;
         }
        labResult.Text = mathopt.GetIt(Convert.ToInt32(txtNumA.Text), Convert.ToInt32

    (txtNumB.Text)).ToString();
    }
    当用户从下拉框中选择一种运算时,使用Assembly类的createInstance方法创建对像,然后再使用它来完成计算,此项目关键点是DynamicCreatorObject项目中没有对MathLibrary项目的引用 ,只有对接口库InterfaceLib的引用,主程序中针对IMathOpt接口编程,没有任何代码绑定到MathLibrary中的具体类型,这就剥离了界面代码与功能代码,使这两者可以独立的变化,比如可以提供多种不同的用户界面,或者提供使用不同的算法实现功能代码,这样整个程序的可扩展性大大增加,不会出现牵一发而动全身的现像。

  • 相关阅读:
    混杂模式
    消息队列学习
    item21
    消息队列改写
    socket select模型
    EffectiveC++ Item11
    How to read a PCap file from Wireshark with C++
    winsock select学习
    线程安全与可重入函数
    process explorer 查看句柄或者加载的dll
  • 原文地址:https://www.cnblogs.com/75115926/p/3172552.html
Copyright © 2011-2022 走看看