`
lovnet
  • 浏览: 6710832 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

C#反射(Reflection),特性(Atrribute)

 
阅读更多

反射定义

反射就是审查元数据并收集关于它的类型信息的能力.

那元数据又是个啥东东呢?元数据是程序集里的东西. 我们知道程序编译之后会生成很多dll,它就是程序集,一般是一个project对应一个程序集吧.一个程序集(assembly)就是一个dll或exe文件(不过据说有多文件程序集,不知道是不是一个程序集是多个dll,没研究过啊).当然不是所有的dll文件都叫程序集.其他程序语言,比如C++中也会有dll,我们一般就叫动态链接库.不是程序集.程序集里除了可执行指令外还有元数据.元数据就是一大堆的表,有类定义表,字段定义表,方法定义表.另外还有版本等信息.它有点像个目录一样,告诉我们程序集中有些啥内容.

我们大部分时候应该是不需要去知道程序集里元数据的信息的.也就是不需要用到反射的.那啥时候需要用反射呢?

正常情况下我们要使用某个dll的话直接添加引用,然后引用命名空间.接下来就可以使用其中的类了.那如果事先约定好某个dll中会有些啥类和函数.但是那dll还没做好.你写代码时又要用到,那咋整啊.总不能傻等着别人做完你再写代码吧.另外如果那dll暂时没打算写,等以后再扩充就更是如此了.这会就可以用到反射了.你可以先写代码Load某个dll(不一定要实际存在),然后获取里面类和函数信息,然后调用.这是调用别的dll时用到,调用本身所在的dll也可以用到反射,比如一般软件都会有个"关于"的菜单选项,点下会弹出软件的版本信息.通过从程序集中可以获取版本信息,不用再去注册表或其他哪去获取了.另外我们用VS时智能感应让我们用起来很方便,随便敲几个字母带出一堆信息.这里也是用到反射.

特性(atrribute)定义

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.LoadFrom(dllPath);

Type yourName = asm.GetType("MyDll.YourName");

Attribute[] notes = Attribute.GetCustomAttributes(yourName);

foreach(var at in notes)

{

MyAtrribute myAt = at as MyAtrribute;

Console.WriteLine(myAt.Note);

}

我们很容易发现这里有个问题,就是必须添加MyDll的引用.不然去哪找到类MyAtrribute啊.

那这样的话如果只是动态加载MyDll该咋整啊.那样就会比较麻烦了.

得这样

string dllPath = @"D:\MyDll.dll";

Assembly asm = Assembly.LoadFrom(dllPath);

Type myAtrribute = asm.GetType("MyDll.MyAtrribute");

MethodInfo myFunction = myAtrribute.GetMethod("ShowNote"); //先要得到特性类中的函数

Type yourName = asm.GetType("MyDll.YourName");

Attribute[] notes = Attribute.GetCustomAttributes(yourName);

foreach(var note in notes)

{

object myObject = (object) note;

myFunction.Invoke(myObject, null); //这里才能得到特性里的内容

}

这样用起来就很麻烦的.不知道有其他啥简单点的方法不.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics