3

AppDomain.CurrentDomain.DomainUnloadクラスの特定のインスタンスや特定のクラスから独立している静的リソースをクリーンアップできるイベントがあります。私はそれを、現在のアセンブリ内のコードの後に​​実行されるコードと見なします (ところで、私は正しいですか?)。

しかし、現在のアセンブリ (クラス ライブラリ) 内の他のコードの前に実行されるコード (現在のアセンブリ用) を記述する方法はありますか? または、コードの実行が開始される前にいくつかのリソースを初期化するためのよりトリッキーな方法を探す必要がありますか?

静的コンストラクターについては知っていますが、それらの呼び出しの順序は明確に定義されていません。つまり、特定の静的コンストラクターが他のクラスの他の静的コンストラクターの前に実行されるという保証はありません。

もありAppDomain.AssemblyLoadます。これが私が探しているものかどうかわかりません。このイベントは、現在のアセンブリではなく、その他のアセンブリが読み込まれたときに発生します。

4

5 に答える 5

2

私も同じ問題を抱えていて、この方法で解決しました。IAssembyInitializerメソッドだけでインターフェースを定義しますvoid Initialize()。ロードされた直後にコードを実行するすべてのアセンブリで、このインターフェイスを実装するクラスを定義します。このインターフェイスを実装するアセンブリ内のクラスを指定するための属性を定義します(そうでない場合は、Reflectionで見つけることができますが、この方法で選択しました)。

[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public class AssemblyInitializerAttribute : Attribute
{
    AssemblyInitializerAttribute ()
    {
    }
    AssemblyInitializerAttribute (string typeName)
    {
        TypeName = typeName;
    }
    public string TypeName;
}

属性は、次のようにAssemblyInfoに設定されます。

[assembly: AssemblyInitializerAttribute ("MyNamespace.AnAssemblyInitializer")]

最後に、アプリケーションのメインアセンブリで、すべての初期化を実行するメソッドをAssemblyLoadイベントに登録します。

AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(NewAssemblyLoaded);

        static void NewAssemblyLoaded(object sender, AssemblyLoadEventArgs args)
        {
            Assembly anAssembly = args.LoadedAssembly;
            AssemblyInitializerAttribute[] initializers = (AssemblyInitializerAttribute[])anAssembly .GetCustomAttributes(typeof(AssemblyInitializerAttribute), false);
            foreach (AssemblyInitializerAttribute anInit in initializers)
            {
                Type initType = anInit.TypeName != null ? anAssembly.GetType(anInit.TypeName) : null;
                if (initType != null && initType.GetInterface("IAssemblyInitializer") != null)
                {
                    IAssemblyInitializer anInitializer = (IAssemblyInitializer)Activator.CreateInstance(initType);
                    anInitializer.Initialize();
                }
            }
        }
于 2013-01-24T13:46:33.913 に答える
1

Lazy<T>hold in static フィールドのインスタンスを使用して、静的な初期化順序を自分で制御できます。Lazy<T>これらの初期化オブジェクトのコード本体は、初期化Lazy<T>の DAG を自動的に調整する他のインスタンスを参照できます。明らかに、サイクルを持つことはできません。

C++/CLI を使用すると、アセンブリのロード時にコードを実行できます (モジュール初期化子)。あなたはおそらくその道を行きたくないでしょう。

C# では、これは不可能です。静的 ctor と遅延初期化パターンが最適です。

于 2013-01-24T13:26:18.180 に答える
0

クラス ライブラリの使用方法を制御できないと仮定すると、ライブラリ内のすべての public/protected クラスの静的コンストラクターを作成し、それらのすべてから初期化コードを呼び出すことができます。明らかに、初期化コードは、(静的フィールドを介して) 最初の呼び出しを追跡して、1 回だけ実行されるようにする必要があります。

于 2013-01-25T06:49:16.757 に答える
0

コードをスキャンして、初期化を完了する必要がある場所を見つけることができます。

次に、初期化がまだ実行されていないときに、必要になる直前に初期化を開始します。

.NET では、アセンブリがいつ読み込まれるかがわからないため、すべてのシナリオで初期化が時間内に開始されるという保証はありません。

別の方法は、アセンブリのクライアントがメソッドを呼び出して初期化を明示的に開始することです。(まだロードされていない場合は、アセンブリもロードされます)

AssemblyLoad イベントは、特定のアセンブリの読み込みを検出するためにクライアントでそのように使用できますが、初期化はクライアントの実装に依存するようになりますが、最初のソリューションでは、この責任はアセンブリ自体の範囲内に保持されます。

于 2013-01-24T13:37:58.230 に答える
-1

Module Initializersでそれを行うことができます。これらは C# では直接サポートされていませんが、Cecilを使用してアセンブリを後処理することに抵抗がない場合は、それらを使用できます。

于 2013-01-24T16:53:50.887 に答える