认识反射

先看段代码:

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, 参数);

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值