web-dev-qa-db-ja.com

アセンブリのロード時にライブラリを初期化します

関数型ライブラリのように機能する.netライブラリdllがあります。静的メソッドに加えて、静的タイプがたくさんあります。

ライブラリを使用できるようにセットアップするために実行する必要のある初期化コードがいくつかあります。

アセンブリがロードされたときに、特定のメソッドが確実に実行されるようにする方法はありますか? AppDomain.AssemblyLoadのようなものですが、アセンブリ自体から自動的に呼び出されます。使用できるAssemblyAttributeのようなものがあるのではないかと思っていました。

現時点では、静的コンストラクターにこの初期化コードがありますが、これは多くのエントリポイントを持つライブラリであるため、この特定のタイプが使用される保証はありません。

ありがとう!

25
sixtowns

データを必要とする最初のタイプが使用されるときだけでなく、データのanyが使用される前に、すべてのデータをロードする必要があるのはなぜですか?

アセンブリ内から、アセンブリのロードでメソッドを強制的に実行する方法はないと思います。静的コンストラクターをevery型に配置することもできますが、率直に言って、そのデータを表し、そのデータへのアクセスを提供する単一の型を用意し、その型のみに静的コンストラクターを配置する方が理にかなっていると思います。 (独立して使用できるデータのビットが別々にある場合は、それらに別々のタイプを作成することもできます。)

7
Jon Skeet

はい、あります-ある種。

Einar Egilssonによる優れた小さなユーティリティを使用してください InjectModuleInitializer

この実行可能ファイルをビルド後のステップとして実行して、パラメーターを受け取らない静的なvoid関数を呼び出す小さな.cctor関数(モジュール初期化関数)を作成します。コンパイラーが.cctor()を作成する機能を提供してくれれば、幸いなことに、この機能が必要になることはめったにありません。

ただし、これは完全なDllMainの置き換えではありません。 CLRは、アセンブリのロード時にではなく、アセンブリで呼び出されるメソッドの前にのみこの.cctor関数を呼び出します。したがって、アセンブリの読み込み時に何かが発生する必要がある場合は、読み込みコードでメソッドを直接呼び出すか、詳細に説明したハックを使用する必要があります https://stackoverflow.com/a/9745422/240845

19
mheyman

次の解決策は、実行中のメインアセンブリを制御できる場合にのみ可能です。つまり、配布用のスタンドアロンライブラリには適していません。

同様の問題が発生し、Typeパラメーターを使用してAssemblyをターゲットとする属性 'InitializeOnLoad'を作成することで解決しました。次に、メインの実行可能ファイルに、簡単なAppDomain.AssemblyLoadedハンドラーを追加しました。このハンドラーは、新しくロードされたアセンブリをスキャンして前述の属性を探し、System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor()を呼び出します。

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class InitializeOnLoadAttribute : Attribute
{
    Type type;

    public InitializeOnLoadAttribute(Type type) { this.type = type; }

    public Type Type { get { return type; } }
}

// somewhere very early in main exe initialization
AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(AssemblyInitializer);

static void AssemblyInitializer(object sender, AssemblyLoadEventArgs args)
{
    // force static constructors in types specified by InitializeOnLoad
    foreach (InitializeOnLoadAttribute attr in args.LoadedAssembly.GetCustomAttributes(typeof(InitializeOnLoadAttribute), false))
        System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(attr.Type.TypeHandle);
}

さらに、AssemblyLoadイベントをフックする前にアセンブリがロードされている可能性がある場合は、AppDomain.GetAssemblies()を実行して、それらの「初期化子」を呼び出すことができます。

11
Stefan Simek

可能です-静的コンストラクターを<Module>クラスに追加するだけです。しかし、ILを変更せずにこれを達成する方法はわかりません。

2
Ark-kun