2010-07-29 58 views
4

在过去的几年中,我偶尔会想知道在.NET世界中可用的(着名的)DLL_PROCESS_ATTACH的等价物。我所说的任何文档都略有简化,最早的类入口点是静态构造函数(cctor),但不能影响when it is called,也不能定义一个保证在任何其他cctor或字段初始化程序之前被调用的cctor ,黑客,如果班级从未使用过,甚至可能根本不会被调用。在调用程序集中的任何方法之前,CLR调用的最早的入口点是什么?

所以,如果你想保证有什么地方初始化之前你组装的任何方法被调用,你不希望有一个cctor添加到您的装配每一个类,你能采取什么办法?或者有没有一个简单的.NET管理解决方案,我错过了这么多年?

+2

为什么?你想做什么? – SLaks 2010-07-29 14:35:46

+1

@SLaks:为什么?在具有多个类的静态实用程序库中,您不希望每个类中的每个方法或cctor都调用全局初始化程序,从而违反DRY。另外,比较现有的'DllMain',它出于某种目的(并且有其缺点)。如果您想钩住或绕行方法或想使用您自己的[AssemblyResolver](http://msdn.microsoft.com/zh-cn/library/system.appdomain.assemblyresolve%28VS.71%29.aspx)或执行其他与装配相关的任务。野外的一些例子是System.Data模块和[msvcm80.dll](http://blogs.msdn.com/b/junfeng/archive/2005/11/19/494914.aspx) – Abel 2010-07-30 10:31:04

回答

4

我通常不回答我自己的问题,但同时我找到了一个没有出现在这里的答案,所以我在这里。

经过一番研究,我偶然发现了this post by Microsoft,这也解释了混合管理的问题和内部DllMain非托管代码和解决方案,这是约与第2版的CLI的,模块初始化。引用:

此初始化运行只是 天然的DllMain之后(换言之,外 装载机锁的),但任何 托管代码运行或管理数据之前是 从该模块访问。模块的 语义。cctor是 非常类似的类.cctors 和定义在ECMA C#和 公共语言基础结构 标准。

虽然我没能找到当前ECMA规范的内部术语模块初始化,从类型初始化合乎逻辑地和全球<Module>特殊类(见22.26的MethodDef,分点40)。 .NET 1.1(即从2.0开始)之后实现了。另请参阅this semi-official description

这个问题不是关于C#,而是因为它是.NET的通用语言:C#不知道全局方法,并且不能创建<Module>,更不用说它的cctor了。但是,Einar Egilsson拥有recognized this apparent deficiency并创建了InjectModuleInitializer.exe,它允许您将其作为Visual Studio的后/编译步骤执行。在C++。NET中,使用这种方法很简单,推荐使用DllMain。另请参阅this SO answer by Ben Voigt(不是接受的答案)和SO answer by yoyoyoyosef

简而言之,模块初始化程序是在加载模块之后调用的第一个方法(不一定在加载程序集时!),并且在调用任何类或实例方法之前调用。它不接受参数,不返回任何值,但可以在其正文中包含任何托管代码。

+0

http://stackoverflow.com/questions/1915506 – user423430 2013-01-22 15:42:35

1

这是通过设计:它最大限度地减少了静态构造函数之间的耦合。你知道你的cctor将在你的类的任何东西初始化之前被调用,并且在你的类使用的任何类的cctors之后。但是,与同一应用程序中无关的类相比,它的运行时间并不能保证。

如果您想确保您的代码在入口点之前运行,请考虑为主应用程序编写包装。一个简单的方法是将它放在一个单独的可执行文件中。

更自足的方式来做到这一点可能是:无论启动代码是必要的,正确的顺序

  1. 运行。不要在不应该​​初始化的程序集中引用任何类型。
  2. 创建自己的应用程序域
  3. 运行此第二应用程序域
+1

这可能是路径采取,我害怕这个答案弹出。当你的程序集本身不是应用程序,或者在托管环境(如ASP.NET)中使用时,单独的可执行文件btw几乎没有用处。 – Abel 2010-07-29 15:28:30

2

内真正的切入点其实这是不完全真实的cctor首先被调用。如果您有通过静态方法将被调用的静态字段初始化。

看一看这段代码:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace CallSequence 
{ 
    internal class Test 
    { 
     internal Test() 
     { 
      Console.WriteLine("non-static constructor"); 
     } 

     static Test() 
     { 
      Console.WriteLine("static constructor"); 
     } 

     static int myField = InitMyField(); 

     static int InitMyField() 
     { 
      Console.WriteLine("static method : (InitMyField)"); 
      return 0; 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      Test t = new Test(); 
     } 
    } 
} 

编辑:也可以考虑使用Factory pattern这将帮助你做所有需要的初始化返回创建的对象了。

+0

道歉,我的笔记*“(简体)”*,在我的第一版中,我被意外删除了。我知道静态字段在静态cctor之前被初始化,并且它们的顺序没有被定义。这仅仅是为了在这之前调用一种方法的更强大的情况。注意:我编辑了我的q。以反映这种明显的不明确性,谢谢提及;-) – Abel 2010-07-29 15:18:34

+0

任何答案如何定义*最早的入口点是什么? – Abel 2010-07-29 15:26:53

+0

最早的入口点是静态初始化器和构造函数我不确定是否需要它,但如果需要执行preinit之类的操作,Factory模式可能会有所帮助。 – Incognito 2010-07-29 15:31:32

相关问题