如何在运行时检查引用的程序集是否可用?

我正在创建一个简单的,独立的.net winforms应用程序。 它引用.Net Framework 4的程序集Microsoft.SqlServer.SqlWmiManagement ,它可能存在于客户端计算机上,也可能不存在。 如果该程序集不存在,那么在运行时我希望我的应用程序优雅地失败而不是崩溃。

我有一个组件开始:

 ... using Microsoft.SqlServer.SqlWmiManagement; ... try { // do something that uses SqlWmiManagement } catch { // handle the missing assembly } 

不幸的是,在我的小块尝试块之前,当组件加载时抛出未处理的exception。

这样做的正确方法是什么?

没有安装程序,这应该是一个拖放exe。

如果未找到程序集,则会触发AssemblyResolve事件。 您可以尝试捕获并退出应用程序。 请参阅此MSDN 。

 public static void Main() { // Note: AssemblyResolve occurs when the resolution of an assembly fails. AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler); } private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args) { if ( args.Name.Contains("SqlWmiManagement")) { // assembly not found } return null; } 

当函数是JIT时抛出exception。 将您的代码更改为:

 void DoSomethingThatUsesSqlWmiManagement_() { ... } void DoSomethingThatUsesSqlWmiManagement() { try { DoSomethingThatUsesSqlWmiManagement_(); } catch { handle the missing assembly } } 

您可能应该只catch特定的Exception

确保包含Main()函数的类不引用与程序集相关的任何内容。

如果它被定义为主表单的一部分,请在自己的类中将其取出。

然后,在方法的最开始使用Assembly.Load()。 您必须将SqlWmiManagement.dll程序集的完全限定名称作为参数传递。

我想我通过纠正代码中的范围来解决这个问题。 使用这篇文章:

https://sites.google.com/site/craigandera/craigs-stuff/clr-workings/dealing-with-assembly-load-failure

我将需要Microsoft.SqlServer.SqlWmiManagement的方法移动到一个单独的类中。 分离它意味着我可以从try {}块内部调用它,该块在导致组件被隐式加载的范围之前开始。 这意味着我可以从失败的程序集负载中捕获exception。

代替:

 using Microsoft.SqlServer.SqlWmiManagement; // .net implicitly loads assembly when current class is instantiated // ... code ... try { // problem method using missing assembly } catch { // this is ineffective because the ass'y load already failed before the try block } 

我以前可以:

 try { // invoke problem method in another class // implicitly loads assembly here instead, inside the try block } catch { // this now catches ass'y load failure } 

虽然@CC Inc的答案在调用Main()后加载引用时有效,但对于使用静态对象或类的引用,需要在调用Main()之前安装ResolveEventHandler 。 你可以试试:

 private static bool gAutoLoad = ExecuteBeforeMain(); private static bool ExecuteBeforeMain() { // Note: AssemblyResolve only occurs when the resolution of an assembly fails. AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolveErrorHandler; return true; } private static System.Reflection.Assembly AssemblyResolveErrorHandler(object sender, ResolveEventArgs args) { ... } 

我不认为有一个保证ExecuteBeforeMain()足够早地执行(在引用尝试加载之前),但是当我包含我的记录器时,它对我有用,如下所示:

 ReferenceNamespace.LoggerClass.StaticActiveLogger.LogMethod(string);