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

时间:2013-02-28 23:39:19

标签: c#

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

我有一个开始的组件:

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

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

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

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

5 个答案:

答案 0 :(得分:7)

如果找不到程序集,则会触发AssemblyResolve事件。您可以尝试捕获并退出应用程序。 See this 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;
}

答案 1 :(得分:2)

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

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

您可能应该catch仅限Exception

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:2)

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

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

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

而不是:

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
}

答案 4 :(得分:0)

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

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()足够早地执行(在尝试加载引用之前),但是当我包含我的记录器时它适用于我,如下所示:< / p>

ReferenceNamespace.LoggerClass.StaticActiveLogger.LogMethod(string);