一篇文章没有读完当然需要接着研究,直到有所收获才对,今天的时间不多,因为阿伟带着朋友过来,一起玩了一个下午,上午读到的一些内容还没有整理。
昨天读到发现的机制,该讲具体做法了,文章提到,.NET没有一个固定的模式用来进行后期的发现,但是提供了多种手段允许用户来做。文章给出了2种手段来做着一件事情,这与上一篇中提到的那个“自相矛盾”的问题紧密相关。
第一种手段:给一个程序集配备一个XML文件,用该文件描述主程序用到的扩展程序集和其中的类型。比如:
<PluginAssembly name="MyPlugin.dll">
<Type name="SomeType"/>
<Type name="AnotherType"/>
</PluginAssembly>
<PluginAssembly name="MorePlugins.dll">
</PluginAssembly>
<PluginAssembly name="MyPlugin.dll">
<Type name="SomeType"/>
<Type name="AnotherType"/>
</PluginAssembly>
<PluginAssembly name="MorePlugins.dll">
</PluginAssembly>
这样主程序自然知道需要的程序集和其中的类型,剩下的事情就好办了,这种发现最直接了当。文章认为这个方法适用于服务器端的扩展,因为一个广泛发布的程序,用户可能不愿意去编写一个.config文件,也就是可用性比较差。
第二种手段:这种手段的程序相当灵活,因此可用性大大提高,这种方法就是采用反射来发现。这种方法的难点有2个,一是发现的标准,二是加载到哪个程序域(AppDomain)中,第二个难点上一篇文章中已经提到并解决了,也就是采用一个专用的程序域。对于我来说,第一个难点需要着重研究。解决第一个难点作者给出了3种可供选择的方法,也就是可通过3种标准来发现:1、接口标准,2、基类标准,3、自定义属性标准。至于到底该用哪一种标准来发现,从文章来看,有一句话是:“更重要的是,可以使用接口和基类以早期绑定的方式调用晚期绑定代码。例如,当您将接口作为绑定到一个对象类型的标准使用时,则可以通过该接口类型的引用来使用对象的实例。这样就可以避免需要使用反射来调用方法和访问实例的其他成员,从而提高可扩展应用程序的性能和代码能力。”[原文:For example, when you use an interface as criteria for binding to an object type, you can use an instance of the object through a reference of the interface type. This avoids the need to use reflection to call methods and access other members of the instance, which improves performance and codeability of your extensible application.]
关于这一段,我的理解是使用接口标准时,能够用接口类型的引用来使用对象实例。具体怎么做我还是有一点不太明白。感觉这样做可以不通过反射来使用实例的方法了,好像不是后期绑定一样,这样当然好……可是怎么做呢,这一段没有说。
接下来讲的是如何确定程序集中的一个类型是否实现了特定的接口,当然这是上述“接口标准”的重要一个步骤,但是仍然没有提到如何调用对象的实例方法。确定程序集中的类型是否实现了一个接口的代码模型如下:
Boolean ImplementsPluginInterface(Type someType){
return typeof(IPlugin).IsAssignableFrom(someType);
}
Boolean ImplementsPluginInterface(Type someType){
return typeof(IPlugin).IsAssignableFrom(someType);
}
这一段代码隐含了知道这个类型的名字了,因为代码中的参数someType是一个类型啊。注意示例代码上面讲述的一段话:“从 Type 派生的类型的每个实例都引用系统中的一个类型。Type 实例可以用于在运行时发现关于该类型的一些事实。”也就是说,GetType返回的都是实例,这些实例代表了什么呢?代表了系统中每一个类型的示例,我理解类型的示例不是类型的对象,好比类型System.Windows.Form.TextBox这个类型,它(本身)的示例是一个文本框,但是它的类型的实例是关于类型的描述。
接下来文章讲了第二个难点的解决方法,这里不重复了。
激活:创建实例和调用方法
一旦确定了要在应用程序中插入哪些类型,接下来就需要创建对象的实例。这完全可以[意思是,所有这一切都可以]通过反射来实现;不过您会发现反射速度慢、不实用,而且难以维护。另外,您还应该选择使用反射来创建插件对象的实例,将对象强制转换为已知接口或基类,然后在其整个剩余生命周期内根据已知类型使用这些对象。请记住,接口和基类标准很适合采用这种方法来发现插件类型。
结合上述的如何实现采用接口标准的论述,给出一段代码的模式,采用这种模式,显然可以像早期绑定那样使用对象实例,然而我不明白的是如果扩展部分的对象是一个继承类的实例,如何能够使用那些扩展的方法,也就是不同于基类的那些方法?对于接口,应该不存在这样的问题,我想。
文章给出的代码如下:
IPlugIn CreatePlugInObject(Type type){
return (IPlugIn) Activator.CreateInstance(type);
}
IPlugIn CreatePlugInObject(Type type){
return (IPlugIn) Activator.CreateInstance(type);
}
这个代码返回的到底是什么呢?应该是一个对象的引用吧。
接下来文章讲述的是有关代码安全性的问题:“保护可扩展性”和“调整安全策略”,前者是原理性的东西,后者是如何实现的手段,有些不太明白,感觉不是很紧要,可以以后再研究。大约意思是.NET很灵活,可以实现某些代码能使用,某些代码不能运行,在发现不能运行的时候,主应用程序捕获一个错误,告诉用户,这个扩展代码的可信级别不够。这样就可以了。
再接下来就是代码的研究,介绍了示例代码的若干特点和方法。
……,可以专门找时间和地点来研究了,
再往下就是推广性的介绍了,结合代码介绍了版本控制、程序健壮性、代码安全性。最后介绍了可卸载的扩展程序集以及给非托管程序编写托管代码的扩展程序集,最后这一点更为复杂,需要更为广泛的知识,先不去深入研究了,估计需要耗费很长时间才能搞清楚一点点眉目,因为又涉及到C++以及COM技术,我估计对这两种技术的要求也不是一般的深度,我知道的那些可能不够用。不过可以先不去研究了。
真好,在整篇的文章给出了一个清晰的编写可扩展应用的框架结构。