4

過去数年間、私は時折DLL_PROCESS_ATTACH、.NETの世界で(不)有名なものに相当するものが利用できるのか疑問に思っていました。クラスへの最初のエントリポイントは静的コンストラクター(cctor)であると私が言っているドキュメントはどれも、それがいつ呼び出されるかに影響を与えることはできません。また、他のcctorよりも先に呼び出されることが保証されている1つのcctorを定義することもできません。またはフィールド初期化子、ハック、クラスが使用されない場合はまったく呼び出されない可能性があります。

したがって、アセンブリのメソッドが呼び出される前に何かが初期化されることを保証し、アセンブリ内のすべてのクラスにcctorを追加する必要がない場合、どのようなアプローチを取ることができますか?それとも、私がここ数年見逃していた.NETの簡単で管理されたソリューションはありますか?

4

3 に答える 3

4

普段は自分の質問には答えないのですが、その間、これまで出てこなかった答えを見つけたので、ここに行きます。

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:

This initializer runs just after the native DllMain (in other words, outside of loader lock) but before any managed code is run or managed data is accessed from that module. The semantics of the module .cctor are very similar to those of class .cctors and are defined in the ECMA C# and Common Language Infrastructure Standards.

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 of DllMain. 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.

于 2010-07-30T10:20:49.307 に答える
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();
        }
    }
}

編集:作成されたオブジェクトを返す前に必要なすべての初期化を行うのに役立つファクトリパターンの使用も検討してください。

于 2010-07-29T14:54:27.790 に答える
1

これは仕様によるものです。静的コンストラクター間の結合を最小限に抑えます。クラス内の何かが初期化される前、およびクラスで使用されるクラスのcctorの後に、cctorが呼び出されることを知っています。ただし、同じアプリケーション内の無関係なクラスと比較して、いつ実行されるかについての保証はありません。

エントリポイントの前にコードが実行されることを確認したい場合は、メインアプリケーションのラッパーを作成することを検討してください。簡単な方法は、別の実行可能ファイルに入れることです。

これを行うためのより自己完結型の方法は、次のとおりです。

  1. 必要なスタートアップコードを正しい順序で実行します。初期化されるべきではないアセンブリ内のタイプを参照しないでください。
  2. 独自のアプリドメインを作成する
  3. この2番目のアプリドメイン内で実際のエントリポイントを実行します
于 2010-07-29T14:51:49.153 に答える