认识反射

先看段代码:

Interface IMedia

{

   Void Play();

   Void Stop();

}

Public class Radio : IMedia

{

Void Play();{….}

   Void Stop();{….}

}

Public class Recorder;: IMedia

{

Void Play();{….}

   Void Stop();{….}

}

Public class MediaFactory

{

       //取得所有播放设备

       Public string[] GetDevicelst() {return new string[]{“Radio”,” Recorder”};

       Public IMedia CreateDevice(string DeviceName)

       {

              If (DeviceName== “Radio”)

                     rturn new Radio();

              else if  (DeviceName== “Recorder”)

                     rturn new Recorder ();

              elser

                     return null;

       }

}

可见页面:

这段代码想必都很熟悉,这就不是个工厂模式么,没错,是个典型的工厂模式,而且还知道不少优点:

1.        采用了接口方式,统一使用IMedia来调用,而不会直接使用RadioRecorder,省了不少代码,不再需要很多重复代码了;

2.        可以方便的扩展啊,比如我再新增一种播放设备的话,只要新增一个类,然后在MediaFactory中加上相应的代码就可以了啊,这对于使用者来说,可以不用修改代码了。

方便,确实方便很多了,但仔细想来啊,又有麻烦了,前面的程序已经开发好了,我要再加一个播放设备,加一个类的话,还得打开原先的代码,加上这个类,然后再MediaFactory中加上创建便个新类的方法,然后再编译后才能使用。

 

能不能简化呢,能不能我这个新的播放类,单独写一下,放到一个新的dll中,然后把这个dll往原先的exe目录中一放,然后就可以调用到这个新的播放类呢,这样我就可以不动原先的程序了呢?

答案是可以的:

       Public string[] GetDevicelst() {return new string[]{“Radio”,” Recorder”};

看到这段代码,我们想到了,这个字符串不就可以保存在配置文件中吧,好,改之:

       Public string[] GetDevicelst() {return Settings.Devicelist.Split(‘;’);}

在配置文件(exe.config)中:

<userSettings>

        <WindowsFormsApplication1.Properties.Settings>

            <setting name=" Devicelist " serializeAs="String">

                <value> Radio ; Recorder </value>

            </setting>

        </WindowsFormsApplication1.Properties.Settings>

    </userSettings>

好,取得设备列表的动态生成搞定了,新增一个类,也只要在这个配置文件里面加个,但看第二个方法CreateDevice,犯难了,在配置文件里面我保存的是类名的字符串,而在这个方法里面得返回其实例,得用new 类名()来创建对象。

这里我们在想是不是有这样一个方法,object instance = CreateInstance(“类名”),这样通过一个字符串,系统就给我返回相应的对象实例。

答案是有的,有这样的方法,这就是反射,我们看下怎么来用。

我们知道,在C#里面类型是随便取的,也就是就可以让两个类型相同,只不过在同一个程序里面,这两个相同的类得用不同的命空间里,在同一程序里,要表达一个类,得用命名空间.类名来表示。

但是在不同的dll中,还是会出现相同的命名空间和类名,所以对于全局来讲,要唯一表过一个类的话,得这样写命名空间.类名,程序集名。一般来说,这要样肯定也就够了,但时,不难保证,我的dll名称也可能相同啊,哦好,加个版本吧:命名空间.类名,程序集名, Version=版本号,那对于.net来说,还有一个多国语言支持呢,我同一批程序同一个版本,不同国家语言的包也可以相同啊,哦好,再加个语言限定吧:命名空间.类名,程序集名, Version=版本号, Culture=neutral这里面的neutral表示本地化的,就是自动读取操作系统的语言。如果再有相同的怎么办呢,没关系,我们可以在这个程序集上加一个guid啊,这个叫做强签名,这样,这个dll中的类就完全唯一了:命名空间.类名,程序集名, Version=版本号, Culture=neutral, PublicKeyToken=null/Guid值。OK,这就是一个类的全名的表示法,当然可以简写,命名空间.类名,程序集名,只要系统中没发现重复的就没事,发现重复的就要报错了的哦。

既然每个类可以用这个长长的字符串来定义的话,在framework中,就有这样一个表示类的类,叫做Type,每一个Type实例都唯一对应着一个类,那么Type对象怎么获取呢,肯定只有在dll(程序集)中找咯,又有一个对象Assembly,这个类是专门来表示程序集的,在这个Assembly中,有一个方法GetTypes,返回这个dll中的所有Type的集合。有了Type对象后就可很方便地创建其实例咯:

Assembly  assembly = Assembly.LoadFile("xxxx.dll");

Type  type = assembly.GetType("Radio");

object instance = Activator.CreateInstance(type);  //创建实例

IMedia media = instance as IMedia;                   

这下好办了,可以能过字符串来取得对象了,好,将前面的代码改造下,连原来的配置文件都不要了:

Public class MediaFactory

{

       //取得所有播放设备, hash表记录所有的设备列表,<名称,类型>

       Public Hashtable GetDevicelst() {

                   Hashtable rtn = new Hashtable();

              foreach (string file in Directory.GetFiles(Application.ExecutablePath, "*.dll"))

{

                 Assembly assembly = Assembly.LoadFile("xxxx.dll");

                 foreach (Type type in assembly.GetTypes())

                 {

                    //判断type是否继承IMedia

                    rtn.Add(type.Name, typ)

                 }

          }

          return rtn;

}

 

       public IMedia CreateDevice(Type type)

       {

              Type  type = assembly.GetType("Radio");

              object instance = Activator.CreateInstance(type);  //创建实例

              return  instance as IMedia;

       }

}

看明白这段代码了吧,这样就实现了前面的要求,丢个dllexe下面,就可以认出里面的IMedia类来并可调用了。

 

既然可以通过字符串来找到程序集,找到里面的类,还能创建具体的实例,那能不能继续,查找到类里有几个函数,有几个属性,然后能否再动态取得你这们实例里面的某个属性值,动态调用类里面的方法呢:

              type.GetProperties();

              type.GetMethods();

              PropertyInfo prop;

              prop.GetValue(obj);

              MethodInfo method;

              method.Invoke(obj, 参数);

看吧,这些方法够你遐想了,尽情地用到你可以简化代码的地方法吧!

反射,在类里面,反过来动态(运行时)找找类本身内部有哪些方法属性等结构!

posted @ 2010-05-06 12:03  JeffreyZhou  阅读(171)  评论(0编辑  收藏  举报