如何检查引用的程序集在运行时是否可用?
本文关键字:运行时 是否 程序集 何检查 检查 引用 | 更新日期: 2023-09-27 18:01:34
我正在创建一个简单的,独立的。net winforms应用程序。它引用了。net Framework 4的汇编Microsoft.SqlServer.SqlWmiManagement
,可能存在也可能不存在于客户端的机器上。如果该程序集不存在,那么在运行时,我希望我的应用程序优雅地失败,而不是崩溃。
我有一个组件开始:
...
using Microsoft.SqlServer.SqlWmiManagement;
...
try {
// do something that uses SqlWmiManagement
}
catch {
// handle the missing assembly
}
不幸的是,在加载组件时抛出了一个未处理的异常,远远早于我的try块。
正确的做法是什么?
没有安装程序,这应该是一个拖放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时抛出异常。将代码改为:
void DoSomethingThatUsesSqlWmiManagement_()
{
...
}
void DoSomethingThatUsesSqlWmiManagement()
{
try
{
DoSomethingThatUsesSqlWmiManagement_();
}
catch
{
handle the missing assembly
}
}
你可能应该catch
只特定的Exception
。
确保包含Main()函数的类没有引用任何与程序集相关的内容。
如果它被定义为主表单的一部分,则将其从自己的类中取出。
然后,在方法的最开始使用Assembly.Load()。您必须将sqlwmimmanagement .dll程序集的完全限定名作为参数传递。
我认为我通过纠正代码中的作用域解决了这个问题。从本文开始:
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
}
虽然@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()
被执行得足够早(在引用试图被加载之前),但它为我工作时,我包括我的日志记录器使用如下:
ReferenceNamespace.LoggerClass.StaticActiveLogger.LogMethod(string);