分享

基础拾忆------反射详解

 weijianian 2016-08-09


来源:kmonkey

链接:cnblogs.com/kmonkeywyl/p/5632911.html


前言


MSDN定义:通过 System.Reflection 命名空间中的类以及 System.Type,您可以获取有关已加载的程序集和在其中定义的类型(如类、接口和值类型)的信息。 您也可以使用反射在运行时创建类型实例,以及调用和访问这些实例。


这句话可以看出反射的命名空间是System.Reflection和System.Type.主要功能是在已经加载的程序集里获取接口、类、方法、字段、属性、特性等类型信息,


1.反射优缺点


1.1.优点:


1、反射提高了程序的灵活性和扩展性。


2、降低耦合性,提高自适应能力。


3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。


1.2.缺点: 


1、性能问题:使用发射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。



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



层次结构


2.System.reflection命名空间


2.1包含的类如下:


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


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


ConstructorInfo 了解如下的类似信息:构造函数的名称、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。


System.Type 的 GetConstructors 或 GetConstructor 方法来调用特定的构造函数。


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


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


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


PropertyInfo 来了解如下的类似信息:属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。


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


3.命名空间System.Type


3.1.Type类的属性:


Name 数据类型名

FullName 数据类型的完全限定名(包括命名空间名)

Namespace 定义数据类型的命名空间名

IsAbstract 指示该类型是否是抽象类型

IsArray   指示该类型是否是数组

IsClass   指示该类型是否是类

IsEnum   指示该类型是否是枚举

IsInterface    指示该类型是否是接口

IsPublic 指示该类型是否是公有的

IsSealed 指示该类型是否是密封类

IsValueType 指示该类型是否是值类型


3.2 Type类的方法:


GetConstructor(), GetConstructors():返回ConstructorInfo类型,用于取得该类的构造函数的信息

GetEvent(), GetEvents():返回EventInfo类型,用于取得该类的事件的信息

GetField(), GetFields():返回FieldInfo类型,用于取得该类的字段(成员变量)的信息

GetInterface(), GetInterfaces():返回InterfaceInfo类型,用于取得该类实现的接口的信息

GetMember(), GetMembers():返回MemberInfo类型,用于取得该类的所有成员的信息

GetMethod(), GetMethods():返回MethodInfo类型,用于取得该类的方法的信息

GetProperty(), GetProperties():返回PropertyInfo类型,用于取得该类的属性的信息     可以调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用     MethodInfo, PropertyInfo和其他类的Invoke()方法。


4.具体用法


4.1、假设你要反射一个 DLL 中的类,并且没有引用它(即未知的类型): 


Assembly assembly = Assembly.LoadFile('程序集路径,即物理路径'); // 加载程序集(EXE 或 DLL) 

object obj = assembly.CreateInstance('类的完全限定名,即包括命名空间'); // 创建类的实例 


4.2、若要反射当前项目中的类(即当前项目已经引用它了)可以为:


Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集 

object obj = assembly.CreateInstance('类的完全限定名,即包括命名空间'); // 创建类的实例,返回为 object 类型,需要强制类型转换


4.3、两者结合:


Type type = Type.GetType('类的完全限定名'); 

object obj = type.Assembly.CreateInstance(type);


5.实例


5.1、创建对象实例


///

    /// 反射帮助类

    ///

    public static class ReflectionHelper

    {

        ///

        /// 创建对象实例

        ///

        ///

        /// 命名空间.类型名

        /// 程序集

        ///

        public static T CreateInstance(string fullName, string assemblyName)

        {

            string path = fullName + '.' + assemblyName;//命名空间.类型名,程序集

            Type o = Type.GetType(path);//加载类型

            object obj = Activator.CreateInstance(o, true);//根据类型创建实例

            return (T)obj;//类型转换并返回

        }


        ///

        /// 创建对象实例

        ///

        /// 要创建对象的类型

        /// 类型所在程序集名称

        /// 类型所在命名空间

        /// 类型名

        ///

        public static T CreateInstance(string assemblyName, string nameSpace, string className)

        {

            try

            {

                string fullName = nameSpace + '.' + className;//命名空间.类型名

                //此为第一种写法

                object ect = Assembly.Load(assemblyName).CreateInstance(fullName);//加载程序集,创建程序集里面的 命名空间.类型名 实例

                return (T)ect;//类型转换并返回

                //下面是第二种写法

                //string path = fullName + ',' + assemblyName;//命名空间.类型名,程序集

                //Type o = Type.GetType(path);//加载类型

                //object obj = Activator.CreateInstance(o, true);//根据类型创建实例

                //return (T)obj;//类型转换并返回

            }

            catch

            {

                //发生异常,返回类型的默认值

                return default(T);

            }

        }

    }


5.2、调用方法实例


public void reflectTest()

        {

            System.Reflection.Assembly ass;

            Type type;

            object obj;

            try

            {

                ass = System.Reflection.Assembly.LoadFile(@'d:\ReflectWyl.dll');

                type = ass.GetType('WebTest.ReflectTest');//必须使用名称空间+类名称

                System.Reflection.MethodInfo method = type.GetMethod('WriteString');//方法的名称

                obj = ass.CreateInstance('WebTest.ReflectTest');//必须使用名称空间+类名称

                string s = (string)method.Invoke(obj, new string[] { 'Wangyanling' }); //实例方法的调用


                //静态方法的调用

                method = type.GetMethod('WriteName');//方法的名称

                s = (string)method.Invoke(null, new string[] { 'Wangyanling' });

                //无参数的实例方法

                method = type.GetMethod('WriteNoPara');

                s = (string)method.Invoke(obj, null);

                // Response.Write(s+'
');

                method = null;

            }

            catch (Exception ex)

            {

            }

            finally

            {

                ass = null;

                type = null;

                obj = null;

            }

        }


5.3、对象转换为Json


对象进行反序列化我们应该在项目中或多火烧都有遇到过,在这当中也是用到了反射不知道,您有没有注意过。现在把对象转为json的实现贴出来,大家根据代码在了解一下反射。


       ///

 

        /// 对象转换为Json 

        ///

 

        /// 对象 

        /// Json字符串 

        public static string ToJson(object jsonObject)

        {

            string jsonString = '{';

            PropertyInfo[] propertyInfo = jsonObject.GetType().GetProperties();

            for (int i = 0; i < propertyinfo.length;="">

            {

                object objectValue = propertyInfo[i].GetGetMethod().Invoke(jsonObject, null);

                string value = string.Empty;

                if (objectValue is DateTime || objectValue is Guid || objectValue is TimeSpan)

                {

                    value = ''' + objectValue.ToString() + ''';

                }

                else if (objectValue is string)

                {

                    value = ''' + ToJson(objectValue.ToString()) + ''';

                }

                else if (objectValue is IEnumerable)

                {

                    value = ToJson((IEnumerable)objectValue);

                }

                else

                {

                    value = ToJson(objectValue.ToString());

                }

                jsonString += '\'' + ToJson(propertyInfo[i].Name) + '\':' + value + ',';

            }

            jsonString.Remove(jsonString.Length - 1, jsonString.Length);

            return jsonString + '}';

        }


5.4、工厂模式


设计模式小提示:



简单工厂:简单实用,但违反开放封闭;


工厂方法:开放封闭,单一产品;


抽象工厂:开放封闭,多个产品;


反射工厂:可以最大限度的解耦。


下面一个例子就是用反射实现工厂模式


namespace FactoryPartern

{

    public interface IFactoryOrg

    {

        IOrg CreateOrg();

    }

    public class FactoryA : IFactoryOrg

    {

        public IOrg CreateVehicle()

        {

            return new A();

        }

    }

    public class FactoryB : IFactoryOrg

    {

        public IOrg CreateVehicle()

        {

            return new B();

        }

    }

    public interface IOrg

    {

        void go();

    }

    public class A : IOrg

    {

        public void go()

        {

            //

        }

    }

    public class B : IOrg

    {

        public void go()

        {

            //

        }

    }

    class ReflectFactory

    {

        public static IOrg CreateOrgByReflect(string typeName)

        {

            string namespaceStr = 'FactoryPartern';

            string tempChar = '.';

            //注意使用Type.GetType(String classname)时,必须指定其命名空间,否则返回为null

            Type type = Type.GetType(namespaceStr + tempChar + typeName, true);


            ConstructorInfo ci = type.GetConstructor(System.Type.EmptyTypes);

            return (IOrg)ci.Invoke(null);

        }

    }

}


进行调用


IOrg org= ReflectFactory.CreateOrgByReflect('A');

           org.go();


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多