反射是.net中的重要机制,通过反射,可以在程序运行的过程中获取程序或程序集中的任何一个类型(如:类、结构、接口、枚举、委托等)的相关信息。换句话说,通过反射,可以对任何一个类型的内部结构了如指掌。
2.反射的作用
1)在程序运行的过程中,动态的创建对象;
2)获取任何类型(如:一个类)中的属性、字段、方法以及构造函数等相关信息;
3)可以动态的调用任何类型(如:一个类)中指定的方法和设置属性的值等;
3.反射实例
接下来将通过一个简单的实例来说明反射在.net中的应用
注释:在.net中使用反射前需要用到System.Reflection的命名空间
1)获取一个类中属性的相关信息
TestClass TC = new TestClass("King",20);
Type t = TC.GetType();
//Get all properties from TestClass
PropertyInfo[] Pis = t.GetProperties();
StringBuilder sb = new StringBuilder();
string GetAllPropertiesStr = string.Empty;
string strFormat = "PropertyName:{0},PropertyValue:{1}/r/n/r/n";
foreach (PropertyInfo temp in Pis)
{
sb.AppendFormat(strFormat, temp.Name, temp.GetValue(TC,null));
}
GetAllPropertiesStr = sb.ToString();
//Get a specified attribute from the TestClass
PropertyInfo p_Name = t.GetProperty("Name");
string GetAttributeValue = p_Name.GetValue(TC,null).ToString();
2)获取一个类中构造函数的相关信息
TestClass TC_a = new TestClass("Queen",120);
Type t = TC_a.GetType();
ConstructorInfo[] Consts = t.GetConstructors();
StringBuilder sb = new StringBuilder();
string strFormat = "Constructor{0}:共有:{1}个参数{2}/r/n/r/n";
int i=0;
foreach (ConstructorInfo temp in Consts)
{
++i;
ParameterInfo[] paras = temp.GetParameters();
string strPara = string.Empty;
foreach (ParameterInfo temp_a in paras)
{
strPara += "," + "参数位置:" + temp_a.Position + "参数名:" + temp_a.Name + "参数类型:" + temp_a.ParameterType;
}
if (paras.Length > 0)
{
sb.AppendFormat(strFormat, i, paras.Length, "分别为:" + strPara);
}
else
{
sb.AppendFormat(strFormat, i, paras.Length, "");
}
}
string resultStr = sb.ToString();
3)获取一个类中方法的相关信息
TestClass TC_b = new TestClass();
Type t = TC_b.GetType();
MethodInfo[] Mis = t.GetMethods();
string strFormat = "方法名:{0},方法返回值:{1},方法参数:{2}"+"/r/n/r/n";
string ParaStr = string.Empty;
StringBuilder sb = new StringBuilder();
foreach (MethodInfo m_Temp in Mis)
{
ParameterInfo[] Params = m_Temp.GetParameters();
foreach (ParameterInfo temp in Params)
{
ParaStr += "," + "参数位置:" + temp.Position + "参数名:" + temp.Name + "参数类型:" + temp.ParameterType;
}
sb.AppendFormat(strFormat, m_Temp.Name, m_Temp.ReturnType,ParaStr.Length>0? ParaStr.Substring(1):"该方法无参数");
}
string resultStr = sb.ToString();
4)通过反射动态创建对象
4.1)使用构造函数动态生成对象
public static void CreateObjectByConstructor()
{
Type t = typeof(TestClass);
//根据参数获取构造函数
ConstructorInfo cons = t.GetConstructor(new Type[2]{typeof(string),typeof(int)});
//设置构造函数所需参数
object[] objArr = new object[2]{"MyBoy",27 };
//调用构造函数生成对象
object GetObj = cons.Invoke(objArr);
//通过生成的对象调用对象中的方法
string GetStr = ((TestClass)GetObj).GetDetailsInfo();
}
4.2)通过Activator动态生成对象
public static void CreateObjectByActivator()
{
Type t = typeof(TestClass);
//设置构造函数所需的参数
object[] objArr = new object[2] {"MyGirl",25 };
//通过Activator的静态方法CreateInstance静态方法,生成新对象
object GetObj = Activator.CreateInstance(t, objArr);
//通过生成的对象调用对象中的方法
string GetStr = ((TestClass)GetObj).GetDetailsInfo();
}
上面介绍的两种动态生成对象的方法,一种是通过构造函数,另外一种是通过Activator的静态方法。通过这两种方法动态生成对象的优点,我认为是可以节省一些内存,因为以往我们使用对象的时候,都是提前的创建,那么程序在运行过程中会为其分配内存空间,而动态的创建就增加了灵活性,也就是说我们只要把动态创建对象的过程封装到一个方法中,只有使用的时候才去调用该方法生成对象,那么就可以减少程序在运行过程中所需的资源。
4.3)通过Assembly类动态生成对象
Assembly ass = Assembly.Load("lib_reflection");
#region 生成对象方式1
Type t = ass.GetType("lib_reflection.TestClass");
object GetObj = Activator.CreateInstance(t, "Super",28);
#endregion
#region 生成对象方式2
object GetObj_b = ass.CreateInstance("lib_reflection.TestClass");
#endregion
//通过生成的对象调用对象中的方法
string GetStr = ((TestClass)GetObj).GetDetailsInfo();
string GetStr_b = ((TestClass)GetObj_b).GetDetailsInfo();
}
从上面的例子大家可以看到,通过Assembly类也可以动态的生成对象,他们的最大的区别就是由Assembly动态生成对象所需要的参数是字符串,而通过上两种方法需要传递的参数需要是一个类,使用类作为参数在使用动态生成对象的时候会受到很多限制,而使用字符串作为参数就显得非常的灵活,只需把要创建对象的类名,以字符串的形式传递给你封装好的创建对象的函数中,那么就可以高效,方便的实现你想要实现的目的。
此外,Assembly类还有一个方法:Assembly.LoadFrom("xxx.dll的路径");该方法是通过加装DLL文件名称返回Assembly对象,然后通过该对象去创建我们需要实例化的对象,通过该方法创建对象主要是针对实例化目标对象的类不在一个项目中,此时不需要再项目中添加引用,就可以动态的创建对象,并调用该对象中的方法,明显的降低程序集之间的耦合。