在调用程序集中的任何方法之前,CLR 最早调用的入口点是什么?
在过去的几年里,我偶尔想知道 .NET 世界中有什么与(臭名昭著的)DLL_PROCESS_ATTACH 等效的东西。我拥有的任何文档都说,稍微简化一下,类的最早入口点是静态构造函数(cctor),但你不能影响 当被调用时,也不能定义一个保证在任何其他 cctor 或字段初始值设定项之前调用的 cctor,hack,它可能不会如果从未使用过该类,甚至根本不会被调用。
因此,如果您想保证在调用程序集的任何方法之前初始化某些内容,并且您不想向程序集中的每个类添加一个 cctor,那么您可以采取什么方法呢?或者 .NET 中是否有一个我多年来一直怀念的简单的托管解决方案?
In the past years I've occasionally been wondering what equivalent of the (in)famous DLL_PROCESS_ATTACH
was available in the .NET world. Any documentation I have says, slightly simplified, that the earliest entry point to a class is the static constructor (cctor), but you cannot influence when it is called, nor can you define one cctor that's guaranteed to be called prior to any other cctor or field initializer, hack, it may not even be called at all if the class is never used.
So, if you want to guarantee something's initialized before any method of your assembly is called and you don't want to have to add a cctor to every class in your assembly, what approach can you take? Or is there an easy, managed solution in .NET that I have missed all these years?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我通常不会回答自己的问题,但同时我确实找到了一个以前没有出现过的答案,所以我开始了。
经过一番研究,我发生在 Microsoft 的这篇文章,其中解释了
DllMain
中混合托管和非托管代码的问题以及解决方案,该解决方案随 CLI 的第二个版本而来,模块初始值设定项。引用:虽然我无法在当前 ECMA 规范中找到术语模块初始化器,但它在逻辑上遵循类型初始化器和全局code> 特殊类(参见第 22.26 节 MethodDef,子点 40)。此功能是在 .NET 1.1 之后(即从 2.0 开始)实现的。另请参阅此半官方说明< /a>.
这个问题与 C# 无关,而是因为它是 .NET 的通用语言:C# 不知道全局方法,并且您无法创建
,更不用说它的 cctor 。然而,Einar Egilsson 认识到了这一明显的缺陷并创建了 InjectModuleInitializer.exe,它允许您作为 Visual Studio 的后/编译步骤来执行此操作。在 C++.NET 中,使用此方法很简单,建议代替DllMain
进行实践。另请参阅Ben Voigt 的回答 (不是公认的答案)和这个 so yoyoyoyosef 的回答。简而言之,模块初始值设定项是在加载模块之后(不一定是在加载程序集时!)、调用任何类或实例方法之前调用的第一个方法。它不接受参数,不返回值,但可以在其主体中包含任何托管代码。
I'd normally not answer my own question, but meanwhile I did find an answer that hasn't come up here before, so here I go.
After some research, I happened on this post by Microsoft, which explains the problems of mixing managed and unmanaged code inside
DllMain
and the solution, which came about with the 2nd version of the CLI, module initializers. Quote:While I wasn't able to find the term module initializer inside the current ECMA specification, it follows logically from type initializer and the global
<Module>
special class (see section 22.26 on MethodDef, sub-point 40). This feature was implemented after .NET 1.1 (i.e., from 2.0 onwards). See also this semi-official description.This question wasn't about C#, but because it is the lingua franca of .NET: C# doesn't know global methods, and you can't create a
<Module>
, let alone its cctor. However, Einar Egilsson has recognized this apparent deficiency and created InjectModuleInitializer.exe that allows you to do this as a post/compile step from Visual Studio. In C++.NET, using this method is trivial and recommended practice in place ofDllMain
. See also this SO answer by Ben Voigt (not the accepted answer) and this SO answer by yoyoyoyosef.In short, the module initializer is the first method that is called after loading the module (not necessarily when loading assembly!) and before calling any class or instance method. It takes no parameters, returns no value, but can contain any managed code in its body.
实际上,首先调用
cctor
并不完全正确。如果您有由静态方法初始化的静态字段,则将调用该静态方法。看看这段代码:
编辑:还可以考虑使用工厂模式 这将帮助您在返回创建的对象之前完成所有需要的初始化。
Actually it is not exactly true that
cctor
is called first. If you have static field initialized by static method that static method will be called.Have a look at this code :
EDIT : Also consider using Factory pattern which will help you do all the needed initialization before returning created object.
这是设计使然:它最大限度地减少静态构造函数之间的耦合。您知道您的 cctor 将在您的类中的任何内容初始化之前以及您的类使用的任何类的 cctor 之后被调用。但与同一应用程序中不相关的类相比,无法保证它何时运行。
如果您想确保某些代码在入口点之前运行,请考虑为主应用程序编写一个包装器。一种简单的方法是将其放入单独的可执行文件中。
一种更独立的方法可能是:
This is by design: it minimises coupling between static constructors. You know that your cctor will be invoked before anything in your class initializes, and after the cctors of any classes used by your class. But there's no guarantee on when it will run compared to unrelated classes in the same application.
If you want to make sure some code of yours runs before the entry point, consider writing a wrapper for the main application. A straightforward way would be to put it in a separate executable.
A more self-contained way to do this might be to: