根据设计模式的原则:1.针对接口编程,而不是针对实现编程。2.优先使用对象组合,而不是类继承。3.封装变化点。
根据上面三个主要的原则,我们我可通过封装变化来减少代码的改动。(通过配置文件来封装变化)。
但是当我们更改配置文件的时候就需要重新加载就会引起重新启动应用程序。为了能够在运行时动态修改配置文件后而不需要重新启动且能立即生效的话,我们就可以用插件来实现。然而是针对.net而言,我们可以把加载的插件放到不同的AppDomain中去,这样就可以防止当插件配置发生更改的时候而不需要重新启动就能使整个应用程序重新生效。
所以:我们需要把具体的目录放到外接程序集,我们可以用Assembly.Load()通常运行良好,但是程序集无法独立卸载(只有Appdomain可以),这意味着如果你正在编写服务器,而且你希望用户无需启动和定制服务器即更新他们的外接程序。那么你将无法使用默认的Appdomain实现此任务。要实现此功能,我们加在一个独立的Appdomain中加载所有外接程序集。当添加或修改文件时,我们将卸载Appdomain,创建新的Appdomain,然后将当前文件加载到其中。
根据这个思想,可以考虑以下解决方案:
我们看看插件的配置:
<Assemblies>
<PluginAssembly AssemblyName="TestXML.exe" AssemblyPath="D:\Downloads\AssemblyLoader\TestXML\bin\Debug\">
<Formats>
<FormatAdapter TypeName="TestXML.Program" RouterTypeName="GetData" />
<FormatAdapter TypeName="TestXML.Program" RouterTypeName="GetName" />
</Formats>
</PluginAssembly>
<PluginAssembly AssemblyName="LibTest.dll" AssemblyPath="D:\Downloads\AssemblyLoader\LibTest\bin\Debug\">
<Formats>
<FormatAdapter TypeName="LibTest.Class1" RouterTypeName="GetData" />
<FormatAdapter TypeName="LibTest.Class1" RouterTypeName="GetData" />
</Formats>
</PluginAssembly>
</Assemblies>
</configuration>
上面的配置文件是插件的配置:(当然可以进行扩展)
下面简单介绍下配置的大体意思:
PluginAssembly节点表示一个插件:
AssemblyName:插件的名称(也就是.exe或.dll)
AssemblyPath:插件配置的路径(AssemblyName所在文件的路径)
Formats:需要在AssemblyName文件中调用的信息
TypeName:指的是AssemblyName的类型定义。
RouterTypeName:指TypeName中方法的定义。
所有上面的配置文件就代表应用程序执行的顺序是这样的:
1.(TextXML.exe)TextXML.Program类中的GetData方法.
2.(TextXML.exe)TextXML.Program类中的GetName方法
3.(LibTest.dll)LibText.Class1类中的GetData方法(因配置一样,所以这个方法将调用两次)
Charles Chen