日期:2014-05-17 浏览次数:20860 次
反射就是审查元数据并收集关于它的类型信息的能力.
那元数据又是个啥东东呢?元数据是程序集里的东西. 我们知道程序编译之后会生成很多dll,它就是程序集,一般是一个project对应一个程序集吧.一个程序集(assembly)就是一个dll或exe文件(不过据说有多文件程序集,不知道是不是一个程序集是多个dll,没研究过啊).当然不是所有的dll文件都叫程序集.其他程序语言,比如C++中也会有dll,我们一般就叫动态链接库.不是程序集.程序集里除了可执行指令外还有元数据.元数据就是一大堆的表,有类定义表,字段定义表,方法定义表.另外还有版本等信息.它有点像个目录一样,告诉我们程序集中有些啥内容.
我们大部分时候应该是不需要去知道程序集里元数据的信息的.也就是不需要用到反射的.那啥时候需要用反射呢?
正常情况下我们要使用某个dll的话直接添加引用,然后引用命名空间.接下来就可以使用其中的类了.那如果事先约定好某个dll中会有些啥类和函数.但是那dll还没做好.你写代码时又要用到,那咋整啊.总不能傻等着别人做完你再写代码吧.另外如果那dll暂时没打算写,等以后再扩充就更是如此了.这会就可以用到反射了.你可以先写代码Load某个dll(不一定要实际存在),然后获取里面类和函数信息,然后调用.这是调用别的dll时用到,调用本身所在的dll也可以用到反射,比如一般软件都会有个"关于"的菜单选项,点下会弹出软件的版本信息.通过从程序集中可以获取版本信息,不用再去注册表或其他哪去获取了.另外我们用VS时智能感应让我们用起来很方便,随便敲几个字母带出一堆信息.这里也是用到反射.
atrribute有时也被翻译成属性,但是容易和property(属性)混淆.atrribute指可以应用到代码块(比如类,方法,属性)上的额外信息.
比如我们在使用序列化的时候会用到特性[Serializable],当要想把某个类序列化必须得在类前面加个这样的特性.特性的用法就是一个中括号号,然后里面加些啥信息.
除了使用类库定义好的特性我们还可以自定义些特性.特性的信息会被保存到程序集中,反射的时候可以用到.
举个简单例子,假如有个dll文件MyDll.dll,里面有个类YourName,类里有个方法ShowYourName().现在想通过动态加载这个dll然后通过反射去实例化类YourName,并调用类中的方法.
dll中类YourName的定义如下
using System;
namespace MyDll
{
class YourName
{
public void ShowYourName()
{
Console.WriteLine("Hi,I am arwen.");
}
}
}
调用的代码如下.先引用命名空间using System.Reflection;
string dllPath = @"D:\MyDll.dll"; //dll文件所在路径
Assembly asm = Assembly.LoadFrom(dllPath); //动态加载dll
Type yourName = asm.GetType("MyDll.YourName"); /*获取类型YourName.Type可以代表反射获得的class,interface等任何类型.有点像object可以代表任何类一样了*/
object obj = Activator.CreateInstance(yourName); //实例化类YourName
MethodInfo function = yourName.GetMethod("ShowYourName"); //获取方法ShowYourName
function.Invoke(obj, null); //调用方法ShowYourName
举个简单的例子,新建一个用来添加注释的特性,其实自定义特性就是新建一个class
class MyAtrribute: Attribute //必须继承Atrribute,其它就跟一般类完全一样
{
public string Note { get; set; }
public MyAtrribute(string msg)
{
Note = msg;
}
public void ShowNote()
{
Console.WriteLine(Note);
}
}
然后在类前面添加
[MyAtrribute("this class is used for showing your name")]
class YourName
{
//就用前面的类YourName
}
在反射中使用自定义特性的信息
string dllPath = @"D:\MyDll.dll";
Assembly asm = Assembly.L