【问题标题】:.Net: Running code when assembly is loaded.Net:加载程序集时运行代码
【发布时间】:2010-10-05 01:11:57
【问题描述】:

是否可以在加载程序集时运行某些代码,而无需在加载代码中执行任何特定操作?我正在寻找的就像一个类型的静态构造函数。

例如:

程序集 A 不知道程序集 B,但 B 确实知道 A。如果加载 B,程序集 A 需要知道关于 B 的某些事情。当运行时(引用或显式)加载程序集 B 时,我希望执行一段代码(静态方法或属性)来调用程序集 A 中的方法。

此问题的根本原因是在序列化 A 中的类型时遇到未知类型,该类型包含 B 中的类型,因为使用接口时编译时未知。

【问题讨论】:

    标签: .net wcf assemblies


    【解决方案1】:

    CLR 支持module initializers。您必须破解 C++/CLI 代码或 ilasm.exe 才能使用它们。

    更新:从 .NET 5 开始,C# 也直接支持 [ModuleInitializer] attribute

    【讨论】:

    • @RichardCollette 它仍在进行黑客攻击,但 Fody 只是将黑客攻击自动化到构建过程中以使其易于执行。
    【解决方案2】:

    您可以在 .Net 中使用静态构造函数,但不幸的是,它们并不能满足您的要求。静态构造函数仅在使用类型之前执行。详情请见http://msdn.microsoft.com/en-us/library/k9x6w0hc(VS.80).aspx

    订阅 AppDomain 的 AssemblyLoad 事件可能会有所收获。见http://msdn.microsoft.com/en-us/library/system.appdomain.assemblyload.aspx

    在您的事件处理程序中,您可以反映新加载的程序集,并让它执行您喜欢的任何代码。

    【讨论】:

    • 不幸的是,由于 30 个奇怪的程序集中只有一个需要完成此注册,因此 AssemblyLoad 可能有点矫枉过正。
    【解决方案3】:

    初始化 .NET 程序集有 3 个选项:

    1. 您在程序集中编写一个静态函数 Init() 或 Main() 以进行初始化,并通过加载此程序集的 C# 代码的反射调用此函数。
    2. 编写托管 C++ 程序集,将代码放入 DllMain()。请小心,因为您的代码将在禁止执行某些操作的加载程序锁中执行(例如加载其他 DLL,...)。但是您可以启动一个新线程来执行任何初始化工作。 (关于 LoaderLock: https://msdn.microsoft.com/en-us/library/ms173266.aspx) (关于 主程序: C# to C++/CLI to C DLL System.IO.FileNotFoundException)
    3. 您编译一个纯 C# 程序集并修改已编译的 DLL 以添加模块初始化程序代码,如下所述: http://einaregilsson.com/module-initializers-in-csharp/ 这种方法的缺点是在程序集加载到进程中时不会立即调用初始化函数。但在首次访问程序集中的任何其他内容之前调用它。

    【讨论】:

    • 1) 可以说不满足“不做任何特定的加载代码?”
    • 不修改加载代码的唯一方法是选项2。)
    • 是的,我非常喜欢你的选项 2
    【解决方案4】:

    (编辑 - 适用于 C#;有关 C++ 方法,请参阅this answer

    基本上,不:你不能。这将是一个巨大的攻击面,并且是不允许的。您可能希望在某些 B 类型上放置一个静态 ctor,以确保执行 init 代码,但仅此而已...

    【讨论】:

    • 似乎很容易在其中隐藏没有代码故意调用的代码 - 难以追踪等。更不用说哪个线程应该运行它的问题了......也许我可以' t 正确地发声,但对我来说这听起来不明智。但这没有实际意义,因为无论如何你都做不到;-p
    • 你知道它是否有任何信息(模块初始化程序不会在 Load 上运行,而是在静态构造函数之前运行),所以如果代码可以在 Load 本身期间运行,这很有趣。如果您要检查是否也可以回答这个非常接近的问题-stackoverflow.com/questions/24718917/…
    【解决方案5】:

    您可能应该重新审视您的序列化方法来缓解这个问题。如果您使用 ISerializableSerializableAttribute 属性进行序列化,则可以使序列化图在必要时加载程序集 B,而无需程序集 A 显式了解程序集 B。

    【讨论】:

    • 如何使用此方法识别和加载程序集 B?
    • 如果您使用 BinaryFormatter 进行序列化,则序列化图中实现 ISerializable 的任何类型都将在反序列化期间调用其构造函数,您可以在其中调用所需的任何代码。因为,当你序列化时,接口的序列化查询......
    • ... A 只通过接口引用 B 的类型也没关系,它们会正确序列化。
    • 我们在 WCF 中使用 XML 序列化。
    • 那么你很可能对这种方法一无所知。有一个 SoapFormatter 可以将 ISerializable 类型持久化为 SOAP XML,并且有在线可用的 XmlFormatter(虽然我不知道它们有多成功)。
    【解决方案6】:

    使用混合程序集,您可以让 DllMain 在程序集负载上运行。

    【讨论】:

      猜你喜欢
      • 2018-04-24
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      • 2012-08-02
      • 1970-01-01
      • 2012-10-15
      相关资源
      最近更新 更多