基础拾遗------反射详解
前言
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、创建对象实例
/// <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();