.net 动态加载Dll - icyjiang - 博客园

来源: .net 动态加载Dll – icyjiang – 博客园

在程序正在使用的过程中,常常需要升级DLL。这时,如果dll已经被主程序引用,则无法修改,这样的需求应该很常见。换个角度,可以理解成程序的升级或者修改Bug的功能。

以下通过动态的加载Dll来解决这个问题。

整个思路的前提是,动态调用的东西和前台需要的功能通过代理IBaseInterface连接起来,也就是说动态dll里面的类和Proxy都需要实现这个接口。

<span class="pln">
</span><span class="kwd">namespace</span><span class="pln"> </span><span class="typ">BaseInterface</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">interface</span><span class="pln"> </span><span class="typ">IBaseInterface</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
</span><span class="kwd">string</span><span class="pln"> </span><span class="typ">GetString</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span>

核心代码:Proxy.dll

<span class="tag"><pre></span><span class="pln">namespace Proxy
{
    internal class AppDomainCore
    {
        public AppDomain DefaultAppDomain { get; private set; }
        public string DefaultAppDomainName { get; private set; }
 
        public AppDomainCore(string appDomainName)
        {
            DefaultAppDomainName = appDomainName;
            AppDomainSetup setup = new AppDomainSetup();
            setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
            setup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
 
            Evidence evidence = new Evidence(AppDomain.CurrentDomain.Evidence);
            DefaultAppDomain = AppDomain.CreateDomain(appDomainName, evidence, setup);
        }
 
        public bool ClearAppDomain()
        {
            try
            {
                AppDomain.Unload(DefaultAppDomain);
                DefaultAppDomain = null;
                return true;
            }
            catch { return false; }
        }
 
        ~AppDomainCore()
        {
            ClearAppDomain();
        }
    }
}</span><span class="tag"></pre></span><span class="pln">
</span><span class="tag"><div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"cnblogs_code_toolbar"</span><span class="tag">><span</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"cnblogs_code_copy"</span><span class="tag">><a</span><span class="pln"> </span><span class="atn">title</span><span class="pun">=</span><span class="atv">"复制代码"</span><span class="tag">><img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"http://www.mikel.cn/wp-content/uploads/2015/05/copycode30.gif"</span><span class="pln"> </span><span class="atn">alt</span><span class="pun">=</span><span class="atv">"复制代码"</span><span class="pln"> </span><span class="atn">data-bd-imgshare-binded</span><span class="pun">=</span><span class="atv">"1"</span><span class="pln"> </span><span class="tag">/></a></span></span><span class="pln">namespace Proxy
{
internal class AssemblyCore
{
public string ActivedAssemblyName { get; private set; }
public string CurrentType { get; private set; }
public FileInfo DefaultAssemblyFile { get; private set; }
 
public AssemblyCore(string assemblyName, string type)
{
ActivedAssemblyName = assemblyName;
CurrentType = type;
 
try
{
DefaultAssemblyFile = new FileInfo(assemblyName);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}</span><span class="tag"></div></span><span class="pln">
</span><span class="tag"><div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"cnblogs_code_toolbar"</span><span class="tag">></div></span><span class="pln">
</span><span class="tag"><div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"cnblogs_code_toolbar"</span><span class="tag">></span><span class="pln">namespace Proxy
{
public class Proxy : BaseInterface.IBaseInterface
{
AssemblyCore _assemblyCore;
AppDomainCore _appDomainCore;
 
public string DefaultAssemblyName { get { return _assemblyCore.ActivedAssemblyName; } }
public string DefaultAppDomainName { get { return _appDomainCore.DefaultAppDomainName; } }
 
public Proxy(string assemblyName, string typeName, string appDomainName)
{
_assemblyCore = new AssemblyCore(assemblyName, typeName);
_appDomainCore = new AppDomainCore(appDomainName);
}
 
public void UnLoad()
{
_appDomainCore.ClearAppDomain();
}
 
BaseInterface.IBaseInterface _proxy;
public string GetString()
{
if (_proxy == null)
_proxy = _appDomainCore.DefaultAppDomain.CreateInstanceFromAndUnwrap(
_assemblyCore.ActivedAssemblyName, _assemblyCore.CurrentType)
as BaseInterface.IBaseInterface;
return _proxy.GetString();
}
}
}</span><span class="tag"></div></span><span class="pln">
</span><span class="tag"><div</span><span class="pln"> </span><span class="atn">class</span><span class="pun">=</span><span class="atv">"cnblogs_code_toolbar"</span><span class="tag">></span>

以上代码在项目Proxy里面写入,是动态加载Dll的核心代码。

在Proxy里面,其中AppDomainCore根据传递的参数生成新的AppDomain, AssemblyCore则根据传递的参数生成新 的FileInfo. 在Proxy类里面,同时定义一个AssemblyCore和AppDomainCore,根据方 法:_appDomainCore.DefaultAppDomain.CreateInstanceFromAndUnwrap(_assemblyCore.ActivedAssemblyName, _assemblyCore.CurrentType), 动态的生成实例,最后用as 转换成接口IBaseInterface,通过调用接口的GetString方法来调用dll里面的方法。

一下为模拟的两个Dll类,

<span class="pln">
</span><span class="kwd">namespace</span><span class="pln"> </span><span class="typ">Assembly1</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
</span><span class="pun">[</span><span class="typ">Serializable</span><span class="pun">]</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ClassLibrary</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">MarshalByRefObject</span><span class="pun">,</span><span class="pln"> </span><span class="typ">BaseInterface</span><span class="pun">.</span><span class="typ">IBaseInterface</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="typ">GetString</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Assembly1.ClassLibrary"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="str"><pre></span><span class="kwd">namespace</span><span class="pln"> </span><span class="typ">Assembly2</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
    </span><span class="pun">[</span><span class="typ">Serializable</span><span class="pun">]</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ClassLibrary</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">MarshalByRefObject</span><span class="pun">,</span><span class="pln"> </span><span class="typ">BaseInterface</span><span class="pun">.</span><span class="typ">IBaseInterface</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="typ">GetString</span><span class="pun">()</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Assembly2.ClassLibrary"</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</</span><span class="pln">pre</span><span class="pun">></span><span class="pln">
</span><span class="pun"><</span><span class="pln">div </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"cnblogs_code_toolbar"</span><span class="pun">><</span><span class="pln">span </span><span class="kwd">class</span><span class="pun">=</span><span class="str">"cnblogs_code_copy"</span><span class="pun">><</span><span class="pln">a title</span><span class="pun">=</span><span class="str">"复制代码"</span><span class="pun">><</span><span class="pln">img src</span><span class="pun">=</span><span class="str">"http://www.mikel.cn/wp-content/uploads/2015/05/copycode30.gif"</span><span class="pln"> alt</span><span class="pun">=</span><span class="str">"复制代码"</span><span class="pln"> data</span><span class="pun">-</span><span class="pln">bd</span><span class="pun">-</span><span class="pln">imgshare</span><span class="pun">-</span><span class="pln">binded</span><span class="pun">=</span><span class="str">"1"</span><span class="pln"> </span><span class="pun">/></</span><span class="pln">a</span><span class="pun">></</span><span class="pln">span</span><span class="pun">></span>

分别生成到Assembly v1.0.dll和Assembly v2.0.dll中。

最终的界面代码:

<span class="pln">
</span><span class="kwd">namespace</span><span class="pln"> </span><span class="typ">DynamicDll</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">partial</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Form1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Form</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
</span><span class="typ">Proxy</span><span class="pun">.</span><span class="typ">Proxy</span><span class="pln"> _proxy</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Form1</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
</span><span class="typ">InitializeComponent</span><span class="pun">();</span><span class="pln">
</span><span class="typ">LoadDll</span><span class="pun">(</span><span class="str">"Assembly v1.0.dll"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Assembly1.ClassLibrary"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Domain1"</span><span class="pun">);</span><span class="pln">
radV1</span><span class="pun">.</span><span class="typ">Click</span><span class="pln"> </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln"> </span><span class="typ">LoadDll</span><span class="pun">(</span><span class="str">"Assembly v1.0.dll"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Assembly1.ClassLibrary"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Domain1"</span><span class="pun">);</span><span class="pln">
radV2</span><span class="pun">.</span><span class="typ">Click</span><span class="pln"> </span><span class="pun">+=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln"> </span><span class="typ">LoadDll</span><span class="pun">(</span><span class="str">"Assembly v2.0.dll"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Assembly2.ClassLibrary"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Domain2"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
 
</span><span class="kwd">void</span><span class="pln"> </span><span class="typ">LoadDll</span><span class="pun">(</span><span class="kwd">string</span><span class="pln"> assName</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> type</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> appName</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">_proxy </span><span class="pun">!=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> _proxy</span><span class="pun">.</span><span class="typ">UnLoad</span><span class="pun">();</span><span class="pln">
_proxy </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Proxy</span><span class="pun">.</span><span class="typ">Proxy</span><span class="pun">(</span><span class="pln">assName</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">,</span><span class="pln"> appName</span><span class="pun">);</span><span class="pln">
lblCurrentAppDomain</span><span class="pun">.</span><span class="typ">Text</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> _proxy</span><span class="pun">.</span><span class="typ">DefaultAppDomainName</span><span class="pun">;</span><span class="pln">
lblCurrentAssembly</span><span class="pun">.</span><span class="typ">Text</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> _proxy</span><span class="pun">.</span><span class="typ">DefaultAssemblyName</span><span class="pun">;</span><span class="pln">
lblMainAppDomain</span><span class="pun">.</span><span class="typ">Text</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">AppDomain</span><span class="pun">.</span><span class="typ">CurrentDomain</span><span class="pun">.</span><span class="typ">FriendlyName</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
 
</span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> btnRes_Click</span><span class="pun">(</span><span class="kwd">object</span><span class="pln"> sender</span><span class="pun">,</span><span class="pln"> </span><span class="typ">EventArgs</span><span class="pln"> e</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
txtRes</span><span class="pun">.</span><span class="typ">Text</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> _proxy</span><span class="pun">.</span><span class="typ">GetString</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span>

 

查看项目Dynamic的依赖项,可以很清楚的看到:它只依赖BaseInterface和Proxy两个项目,与Assembly v1.0和v2.0都无关。

也就是说,程序运行的时候,可以修改Assembly v1.0和v2.0里面的代码,重新生成,同时替换运行目录下的dll。

 

赞(0) 打赏
分享到: 更多 (0)

相关推荐

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

登录

注册