>我正在开发一个类库(MyClassLibrary).
>我依赖于第三方类库(ThirdPartyClassLibrary).
>我需要使用与用户相同版本的ThirdPartyClassLibrary.例如,如果我在ThirdPartyClassLibrary中设置静态值,则用户需要看到该更改.
>我的类的用户可能取决于ThirdPartyClassLibrary的4个不同版本中的任何一个.
> ThirdPartyClassLibrary很大,我不想用我的软件分发它.
>我已经反映了所有4个版本的ThirdPartyClassLibrary,并验证我将要做的事情与所有版本兼容(接口是一样的,方法签名是一样的).
>我需要调用ThirdPartyClassLibrary来执行性能!每当我需要打电话时,我都无法反思一切.
> MyClassLibrary将在运行时被加载,所以我不能指望用户混淆程序集绑定重定向或其他开发时间设置(或任何设置,我的用户都拒绝做任何事情).
>我希望从编译时检查我的代码中受益,所以理想的是没有反思.
>我依赖于第三方类库(ThirdPartyClassLibrary).
>我需要使用与用户相同版本的ThirdPartyClassLibrary.例如,如果我在ThirdPartyClassLibrary中设置静态值,则用户需要看到该更改.
>我的类的用户可能取决于ThirdPartyClassLibrary的4个不同版本中的任何一个.
> ThirdPartyClassLibrary很大,我不想用我的软件分发它.
>我已经反映了所有4个版本的ThirdPartyClassLibrary,并验证我将要做的事情与所有版本兼容(接口是一样的,方法签名是一样的).
>我需要调用ThirdPartyClassLibrary来执行性能!每当我需要打电话时,我都无法反思一切.
> MyClassLibrary将在运行时被加载,所以我不能指望用户混淆程序集绑定重定向或其他开发时间设置(或任何设置,我的用户都拒绝做任何事情).
>我希望从编译时检查我的代码中受益,所以理想的是没有反思.
如何编写MyClassLibrary,以便在加载进程时,用户加载的ThirdPartyClassLibrary的任何版本都能正常工作?
解决方法
一个解决办法是在运行时使用
AppDomain.AssemblyResolve 事件.每当装配体的分辨率失败时,都会触发.您可以使用它将不同版本的程序集加载到CLR尝试加载的程序集.
我在GitHub上添加了一个非常简单的演示:
https://github.com/danmalcolm/AssemblyResolutionDemo
这个设置如下:
>主要应用程序App.exe直接引用程序集ThirdPartyLibrary.dll 2.0.0.0版.
>它还引用了MyLibrary,它引用了旧版本的ThirdPartyLibrary 1.0.0.0版本.
> AppDomain.AssemblyResolve事件用于重定向到版本1.0.0.0无法加载时应用程序使用的版本
AssemblyResolve的处理方式如下:
public static void Initialise() { AppDomain.CurrentDomain.AssemblyResolve += ResolveThirdPartyLibrary; } private static Assembly ResolveThirdPartyLibrary(object sender,ResolveEventArgs args) { // Check that CLR is loading the version of ThirdPartyLibrary referenced by MyLibrary if (args.Name.Equals("ThirdPartyLibrary,Version=1.0.0.0,Culture=neutral,PublicKeyToken=fbcbfac3e44fefed")) { try { // Load from application's base directory. Alternative logic might be needed if you need to // load from GAC etc. However,note that calling certain overloads of Assembly.Load will result // in the AssemblyResolve event from firing recursively - see recommendations in // http://msdn.microsoft.com/en-us/library/ff527268.aspx for further info var assembly = Assembly.LoadFrom("ThirdPartyLibrary.dll"); return assembly; } catch (Exception exception) { Console.WriteLine(exception); } } return null; }
我们需要绑定到在加载ThirdPartyLibrary之前的事件,因此显式的Initialise方法.
还要注意,事件只有在组件的分辨率失败时才会触发.如果MyClassLibrary(1.0.0.0)引用的ThirdPartyLibrary的版本在GAC中可用,那么它将被成功加载,而AssemblyResolve将不会触发.那么使用中会有两种不同的版本.
我在这里展示这种机制可以使用,我不是说这是一个好主意.您需要根据应用程序运行的环境及其设置/安装/维护等方式考虑几件事情.