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

前言

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

这句话可以看出反射的命名空间是System.ReflectionSystem.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、创建对象实例

    /// <summary>
    /// 反射帮助类
    /// </summary>
    public static class ReflectionHelper
    {
        /// <summary>
        /// 创建对象实例
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="fullName">命名空间.类型名</param>
        /// <param name="assemblyName">程序集</param>
        /// <returns></returns>
        public static T CreateInstance<T>(string fullName, string assemblyName)
        {
            string path = fullName + "." + assemblyName;//命名空间.类型名,程序集
            Type o = Type.GetType(path);//加载类型
            object obj = Activator.CreateInstance(o, true);//根据类型创建实例
            return (T)obj;//类型转换并返回
        }

        /// <summary>
        /// 创建对象实例
        /// </summary>
        /// <typeparam name="T">要创建对象的类型</typeparam>
        /// <param name="assemblyName">类型所在程序集名称</param>
        /// <param name="nameSpace">类型所在命名空间</param>
        /// <param name="className">类型名</param>
        /// <returns></returns>
        public static T CreateInstance<T>(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+"<br>");
                method = null;
            }
            catch (Exception ex)
            {
               
            }
            finally
            {
                ass = null;
                type = null;
                obj = null;
            }
        }

5.3、对象转换为Json

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

  /// <summary> 
        /// 对象转换为Json 
        /// </summary> 
        /// <param name="jsonObject">对象</param> 
        /// <returns>Json字符串</returns> 
        public static string ToJson(object jsonObject)
        {
            string jsonString = "{";
            PropertyInfo[] propertyInfo = jsonObject.GetType().GetProperties();
            for (int i = 0; i < propertyInfo.Length; i++)
            {
                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();

以上举得一些简单的例子用来帮助理解,如果有什么不足的地方欢迎拍砖。也可以QQ与我联系。

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java 源码分析

SpringBoot 笔记(十):错误处理

2187
来自专栏项勇

笔记10 | 学习整理静态static 和 终态final

1165
来自专栏Bug生活2048

Spring Boot学习笔记(六)结合MyBatis实现较为复杂的RESTful API

首先看下要实现的效果吧,完成下面截图部分的API,除了CRUD之外,分页查询也是使用的比较多的。

642
来自专栏me的随笔

ASP.NET MVC5中View-Controller间数据的传递

使用ASP.NET MVC做开发时,经常需要在页面(View)和控制器(Controller)之间传递数据,那么都有哪些数据传递的方式呢?

581
来自专栏JMCui

SpringMVC 异常处理.

一、异常处理 Spring提供了多种方式将异常转换为响应: 特定的Spring异常将会自动映射为指定的HTTP状态码     在默认情况下,Spring会将自身...

2938
来自专栏林德熙的博客

win10 uwp 反射

本文在h神的指导下完成。 反射是强大的好用的,我们可以添加新功能不修改之前的代码,通过使用反射得到。 本文下面和大家说如何做一个和WPF一样的反射功能,如何才能...

472
来自专栏青枫的专栏

day17_Listener与Filter学习笔记

    事件:就是一个事情。     事件源:产生这个事情的源头。     监听器:用于监听指定的事件的对象。(关联事件和事件源)     注册监听:要想让监听...

351
来自专栏古时的风筝

ASP.NET-自定义HttpModule与HttpHandler

在之前的ASP.NET是如何在IIS下工作的这篇文章中介绍了ASP.NET与IIS配合工作的机制,在http请求经过一系列处理后,最后到达ASP.NET管道中...

2348
来自专栏hbbliyong

C#基础知识回顾-- 反射(3)

获取Type对象的构造函数: 前一篇因为篇幅问题因为篇幅太短被移除首页,反射这一块还有一篇“怎样在程序集中使用反射”, 其他没有什么可以写的了,前两篇主要是铺...

2706
来自专栏微信公众号:Java团长

Java中的反射机制

反射,当时经常听他们说,自己也看过一些资料,也可能在设计模式中使用过,但是感觉对它没有一个较深入的了解,这次重新学习了一下,感觉还行吧!

671

扫码关注云+社区