.net CLR在调用程序集中的任何方法之前调用的最早入口点是什么?

wydwbb8l  于 2023-04-13  发布在  .NET
关注(0)|答案(3)|浏览(130)

在过去的几年里,我偶尔会想,在.NET世界中可以使用著名的DLL_PROCESS_ATTACH。(cctor),但你不能影响when it is called,也不能定义一个cctor,保证在任何其他cctor或字段初始化器之前被调用,如果该类从未被使用,则甚至根本不会调用它。
所以,如果你想保证在调用你的程序集的任何方法之前初始化某个东西,并且你不想在你的程序集中的每个类中添加一个cctor,你可以采取什么方法?或者在.NET中有一个简单的,托管的解决方案,我错过了这么多年?

1mrurvl1

1mrurvl11#

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

经过一些研究,我发现了this post by Microsoft,它解释了DllMain中混合托管和非托管代码的问题以及解决方案,这是第二版CLI,模块初始化器
这个初始化器刚好在本机DllMain之后运行(换句话说,在加载器锁之外),但在任何托管代码运行或从该模块访问托管数据之前。module .cctor的语义与class .cctors的语义非常相似,并且在ECMA C#和公共语言基础设施标准中定义。
虽然我在当前的ECMA规范中找不到术语 module initializer,但它在逻辑上是从 type initializer 和全局<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中作为一个post/compile步骤来做这件事。在C++.NET中,使用这个方法是微不足道的,建议用这个方法来代替DllMain。另见Ben Voigt的这个SO答案(不是公认的答案)和Yoyoyoyosef的这个SO答案。
简而言之,module initializer 是在加载模块之后(不一定是在加载程序集的时候!)调用任何类或示例方法之前调用的第一个方法。它不接受参数,不返回值,但可以在其主体中包含任何托管代码。

pdsfdshx

pdsfdshx2#

实际上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();
        }
    }
}

EDIT:也可以考虑使用Factory pattern,这将帮助您在返回创建的对象之前完成所有需要的初始化。

zphenhs4

zphenhs43#

这是通过设计:它最小化了静态构造函数之间的耦合。你知道你的cctor将在你的类中的任何东西初始化之前被调用,并且在你的类使用的任何类的cctor之后被调用。但是与同一个应用程序中不相关的类相比,它不能保证什么时候运行。
如果你想确保你的一些代码在入口点之前运行,考虑为主应用程序编写一个 Package 器,一个直接的方法是把它放在一个单独的可执行文件中。
一个更独立的方法可以做到这一点:
1.以正确的顺序运行任何需要的启动代码。不要引用程序集中不应该初始化的任何类型。
1.创建您自己的应用程序域
1.在第二个应用程序域中运行真实的的入口点

相关问题