什么是Reflection?
.NET反射的定义:审查元数据并收集关于它的类型信息的能力
什么是元数据?
元数据是一种二进制信息,用以对存储在公共语言运行库可移植可执行文件 (PE) 文件或存储在内存中的程序进行描述。将代码编译为 PE 文件时,便会将元数据插入到该文件的一部分中。而将代码转换为中间语言 (MSIL) 并将其插入到该文件的另一部分中。在模块或程序集中定义和引用的每个类型和成员都将在元数据中进行说明。当执行代码时,运行库将元数据加载到内存中,并引用它来发现有关代码的类、成员、继承等信息。
元数据以非特定语言的方式描述在代码中定义的每一类型和成员。元数据存储以下信息:
1.标识(名称、版本、区域性、公钥)
2.导出的类型
1.名称、可见性、基类和实现的接口
2.成员(方法、字段、属性、事件、嵌套的类型)
3.该程序集所依赖的其他程序集
4.运行所需的安全权限
.NET反射的作用:
1.可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现 有对象中获取类型。
2.应用程序需要在运行时从某个特定的程序集中载入一个特定的类型,以便实现某个任务时可以用到反射。
3.反射主要应用与类库,这些类库需要知道一个类型的定义,以便提供更多的功能。
应用程序结构:
应用程序域包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。
程序集包含模块,而模块包含类型,类型又包含成员,反射则提供了封装程序集、模块和类型的对象。
我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象或从现有对象中获取类型,然后调用类型的方法或访问其字段和属性。
我们有这么一个类库:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Calculator
{
public interface Iwel
{
String Print();
}
public class Arithmeetic : Iwel
{
/// <summary>
/// 没有带参数的构造方法
/// </summary>
public Arithmeetic()
{ }
/// <summary>
/// 带参数的构造方法
/// </summary>
/// <param name="num1"></param>
/// <param name="num2"></param>
public Arithmeetic(int num1, int num2)
{
_num1 = num1;
_num2 = num2;
}
private int _num1;
/// <summary>
/// _num1属性
/// </summary>
public int Num1
{
get { return _num1; }
set { _num1 = value; }
}
private int _num2;
/// <summary>
/// _num2属性
/// </summary>
public int Num2
{
get { return _num2; }
set { _num2 = value; }
}
public String Add(int num1, int num2)
{
Console.WriteLine("{0}+{1}={2}", num1, num2, num1 + num2);
return ";Add(int num1,int num2)方法是一个公有的带参数的方法";
}
private string Add()
{
return "Add()方法是一个私有的不带参数的方法";
}
private void Subtration(int num1, int num2)
{
Console.WriteLine("{0}-{1}={2};+Subtration(int num1, int num2)" + "方法是一个私有的不带参数的方法", num1, num2, num1 - num2);
}
public static void Multiplication(int num1, int num2)
{
Console.WriteLine("{0}*{1}={2};Multiplication(int num1,int num2)" + "方法是一个公有的带参数的静态方法", num1, num2, num1 * num2);
}
private static void Multiplication()
{
Console.WriteLine("Multiplication()方法是一个私有的不带参数的静态方法");
}
public String Writ()
{
return "Writ()方法是一个公有的不带参数的方法";
}
#region Iwel成员
public String Print()
{
return "欢迎你的使用接口";
}
#endregion
}
}
现在我们来看怎么用反射调用这个类库:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
delegate void TestDelegate(int num1, int num2);
static void Main(string[] args)
{
Assembly assembly = Assembly.LoadFrom("Calculator.dll");//加载程序集
Console.WriteLine("得到Calculator.dll中所有的类");
Console.WriteLine("******************************************");
foreach (Type item in assembly.GetTypes())
{
Console.WriteLine(item.Name + "是Calculator命名空间下的类");
}
Console.WriteLine("******************************************");
Console.WriteLine("得到Calculator.dll中的模块集");
Module[] modules = assembly.GetModules();//得到Calculator.dll中的模块集
foreach (Module item in modules)
{
Console.WriteLine(item.Name + "是Calculator中的一个模块");
}
Console.WriteLine("******************************************");
Console.WriteLine("");
Type[] temp = assembly.GetTypes();
Type type = temp[1];//typeof(Calculator.Arithmeetic);//得到具体的类的类型,如果是反编译怎么写?
Console.WriteLine("具体的类的类型是"+type.Name);
Console.WriteLine("{0}\t是不是public类型\t{1}", type, type.IsPublic);
Console.WriteLine("{0}\t是不是private类型\t{1}",type,type.IsNotPublic);
Console.WriteLine("******************************************");
Console.WriteLine("");
PropertyInfo[] memberInfo = type.GetProperties();//得到类中的属性
foreach (PropertyInfo item in memberInfo)
{
Console.WriteLine(type+"类的属性有"+item.Name);
}
Console.WriteLine("******************************************");
Console.WriteLine("");
Type[] t = type.GetInterfaces();//得到接口
foreach (Type item in t)
{
Console.WriteLine(item.Name + "是Calculator.dll中的接口");
}
Console.WriteLine("******************************************");
Console.WriteLine("");
Console.WriteLine("方法的返回类型,方法传参的类型");
//查找私有方法
MethodInfo[] method = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);
foreach (MethodInfo item in method)
{
Console.WriteLine("私有的方法:\t方法名={0}\t方法的信息={1}", item.Name, item);
}
//查找公有方法
MethodInfo[] methodpublic = type.GetMethods(BindingFlags.Instance | BindingFlags.Public);
foreach (MethodInfo item in methodpublic)
{
Console.WriteLine("公有的方法:\t方法名={0}\t方法的信息={1}", item.Name, item);
}
//查找公有的静态方法
MethodInfo[] methodstatic = type.GetMethods(BindingFlags.Public | BindingFlags.Static);
foreach (MethodInfo item in methodstatic)
{
Console.WriteLine("公有静态方法:\t方法名={0}\t方法的信息={1}", item.Name, item);
}
//查找私有的静态方法
MethodInfo[] methodprivatestatic = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Static);
foreach (MethodInfo item in methodprivatestatic)
{
Console.WriteLine("私有静态方法:\t方法名={0}\t方法的信息={1}", item.Name, item);
}
Console.WriteLine("******************************************");
Console.WriteLine("这是静态方法的形式");
ConstructorInfo[] con = type.GetConstructors();//获得·构造函数的形式
foreach (ConstructorInfo item in con)
{
Console.WriteLine(item);
}
Console.WriteLine("******************************************");
object obj = Activator.CreateInstance(type, null);//创建一个不带参数的实例
MethodInfo men1 = type.GetMethod("Add");
Console.WriteLine("调用{0}方法",men1);
object[] nums1 = { 5, 4 };//参数
Console.WriteLine(men1.Invoke(obj, nums1));
Console.WriteLine("******************************************");
//私有的非静态方法的调用
MethodInfo men2 = type.GetMethod("Add", BindingFlags.Instance | BindingFlags.NonPublic);
Console.WriteLine(men2.Invoke(obj, null));
Console.WriteLine("******************************************");
//公有的静态带参数的方法调用
MethodInfo men3 = type.GetMethod("Multiplication", BindingFlags.Public | BindingFlags.Static);
object[] nums2 = { 5, 6 };
men3.Invoke(null, nums2);
Console.WriteLine("******************************************");
//私有静态的
MethodInfo men4 = type.GetMethod("Multiplication", BindingFlags.NonPublic | BindingFlags.Static);
men4.Invoke(null, null);
Console.WriteLine("******************************************");
//动态创建一个委托
Console.WriteLine("动态声明的一个委托");
TestDelegate dele = (TestDelegate)Delegate.CreateDelegate(typeof(TestDelegate), obj, "Subtration");
dele(9, 3);
}
}
}