gpt4 book ai didi

c# - 在类库中的何处处理 AssemblyResolve 事件?

转载 作者:行者123 更新时间:2023-11-30 17:14:08 25 4
gpt4 key购买 nike

我需要动态解析从一个类库到另一个类库的程序集引用。类库是从 PowerShell 脚本加载的,因此在可执行文件中查找依赖程序集的默认 .NET 行为直接失败,因为可执行文件本身就是 PowerShell。如何使这些依赖程序集引用正确解析/工作?

更详细:

我有两个实用程序库:一个是核心库,另一个是执行一些非常具体的解析任务的库。我想在 PowerShell 脚本中动态加载它们而不是在 GAC 中安装它们。第二个库依赖于第一个。在VS解决方案中,解析库有对核心库的项目引用,Copy Local = true

在使用(此处为 PowerShell)后,我可以从解析库输出 bin (/Debug|/Release) 文件夹中加载和使用这两个库:

[Reflection.Assembly]::LoadFile("C:\...thefile.dll")

但是,无论何时在解析(依赖)库中调用从核心库中调用某些内容的方法,它都无法解析核心程序集。这很……令人沮丧……因为这些文件位于同一个文件夹中。一个或两个是否具有强名称 key 都没有区别。

我现在的解决方法是处理 AssemblyResolve 事件。棘手的事情是弄清楚将它放在类库中的什么位置,因为没有一个入口点总是在任何其他事情之前执行,就像在可执行的 Main() 方法中一样(参见 Is there an equivalent of Application_Start for a class library in c# ).

现在我已经创建了一个静态 Resolver 类,它带有一个静态构造函数,它为 AssemblyResolve 附加了一个处理程序,然后在每个解析类中都有一个静态构造函数它引用静态解析器类,强制执行解析器类的静态构造函数。结果是 AssemblyResolve 事件仅附加一次并使用通用的中央代码进行处理。所以它有效。但我讨厌必须向我所有的解析类添加一个时髦的静态构造函数。

有没有更好的方法来处理这个问题?

最佳答案

我找到了一个遵循“消费者应该解决”模式的解决方案,它适用于 PowerShell 和普通 .NET 应用程序消费者。

想法:

  • 创建一个具有内部 AssemblyResolve 事件处理程序的类,以及一个将处理程序附加到 AppDomain.CurrentDomain.AssemblyResolve 事件的静态构造函数。 (到目前为止这是熟悉的。)
  • 不是从同一个或另一个类库中调用 Resolver 类,由消费者直接调用。当 PowerShell 是使用者时,从 PowerShell 调用 Resolver
  • 之所以可行,是因为任何使用者(包括 PowerShell)都与其加载的程序集具有相同的 CurrentDomain。因此,即使事件处理程序附加在某个动态加载的程序集中,当程序集解析在主要消费应用程序中失败时,它仍会被调用。

我的 Resolver 版本有:

  • 静态属性 AssemblyDirectory 可用于选择性地设置要搜索的目录。如果留空,它将使用从 Assembly.GetCallingAssembly().Location
  • 找到的目录
  • 一个虚拟的 Register() 方法,除了确保已调用静态构造函数外,它实际上什么都不做。

PowerShell 代码:

# First, load the assembly with the Resolver class. I actually put it in the same 
# core library, but it really doesn't matter where it is. It could even be by itself
# in a dynamically compiled assembly built using the Add-Type commandlet
[Reflection.Assembly]::LoadFile("[an assembly that has the Resolver class].dll")

# Call the Register method to force the static constructor to run if it hasn't already
[mycorp.mylib.Resolver]::Register()

$sourcedir = "C:\foo\bar\..some random dir"
# Set the path to search for unresolved assemblies
[mycorp.mylib.Resolver]::AssemblyDirectory = $sourcedir

# Load the dependent assembly
[Reflection.Assembly]::LoadFile("$sourcedir\myparser.dll")

# Create and use an object from the dependent assembly. When the core assembly
# fails at first to resolve, the Resolver's handler is automatically called,
# and everything is peachy
$encoder = New-Object mycorp.mylib.anamespace.aclass
$result = $encoder.DoStuff( $x, $y, $z ... etc )

如果您想知道如何实际处理 AssemblyResolve 事件,请查看 MSDN 上的文档: AppDomain.AssemblyResolve Event

关于Register-ObjectEvent:

起初,我尝试直接在 PowerShell 中构建程序集解析器,并使用 Register-ObjectEvent commandlet 注册它。这可行,但有一个问题:PowerShell 不支持返回值的事件处理程序。 AssemblyResolve 处理程序返回一个 Assembly 对象。这几乎就是他们的全部目的。

关于c# - 在类库中的何处处理 AssemblyResolve 事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9099309/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com