6

わかりましたので、眉をひそめた次の問題に遭遇しました。

さまざまな理由から、TestingAssembly.dll の Testing クラスが BaseTestingAssembly.dll の TestingBase クラスに依存するテスト セットアップがあります。その間に TestBase が行うことの 1 つは、それ自体と呼び出し元のアセンブリで特定の埋め込みリソースを探すことです。

したがって、私の BaseTestingAssembly には次の行が含まれていました...

public class TestBase {    
  private static Assembly _assembly;
  private static Assembly _calling_assembly;

  static TestBase() {
    _assembly = Assembly.GetExecutingAssembly();
    _calling_assembly = Assembly.GetCallingAssembly();
  }
}

私が考えたので、これらのアセンブリはアプリケーションの存続期間中同じであるため、すべてのテストでそれらを再計算する必要はありません。

ただし、これを実行すると、_assembly と _calling_assembly の両方がそれぞれ BaseTestingAssembly と TestingAssembly ではなく BaseTestingAssembly に設定されていることに気付きました。

変数を非静的に設定し、通常のコンストラクターで初期化するとこれが修正されましたが、なぜこれが始まったのか混乱しています。静的コンストラクターは、静的メンバーが初めて参照されたときに実行されると思いました。これは、呼び出し元である必要がある私の TestingAssembly からのみ可能でした。何が起こったのか知っている人はいますか?

4

3 に答える 3

6

静的コンストラクターは、ユーザー コードによって直接ではなく、ランタイムによって呼び出されます。これは、コンストラクターでブレークポイントを設定し、デバッガーで実行することで確認できます。呼び出しチェーンのすぐ上の関数はネイティブ コードです。

編集:静的初期化子が他のユーザー コードとは異なる環境で実行される方法はたくさんあります。他のいくつかの方法は

  1. マルチスレッドに起因する競合状態から暗黙的に保護されています
  2. 初期化子の外から例外をキャッチすることはできません

一般に、あまりにも洗練されたものには使用しない方がよいでしょう。次のパターンで single-init を実装できます。

private static Assembly _assembly;
private static Assembly Assembly {
  get {
    if (_assembly == null) _assembly = Assembly.GetExecutingAssembly();
    return _assembly;
  }
}

private static Assembly _calling_assembly;
private static Assembly CallingAssembly {
  get {
    if (_calling_assembly == null) _calling_assembly = Assembly.GetCallingAssembly();
    return _calling_assembly;
  }
}

マルチスレッド アクセスが予想される場合は、ロックを追加します。

于 2008-09-23T16:17:23.253 に答える
1

Assembly.GetCallingAssembly() は、コール スタックの 2 番目のエントリのアセンブリを返すだけです。これは、メソッド/ゲッター/コンストラクターがどのように呼び出されるかによって大きく異なります。これは、ライブラリにない最初のメソッドのアセンブリを取得するためにライブラリで行ったことです。(これは静的コンストラクターでも機能します。)

private static Assembly GetMyCallingAssembly()
{
  Assembly me = Assembly.GetExecutingAssembly();

  StackTrace st = new StackTrace(false);
  foreach (StackFrame frame in st.GetFrames())
  {
    MethodBase m = frame.GetMethod();
    if (m != null && m.DeclaringType != null && m.DeclaringType.Assembly != me)
      return m.DeclaringType.Assembly;
  }

  return null;
}
于 2008-12-04T16:07:38.727 に答える
1

答えはC# static constructorsの議論にあると思います。私の最善の推測は、次の理由により、静的コンストラクターが予期しないコンテキストから呼び出されていることです。

ユーザーは、静的コンストラクターがプログラムで実行されるタイミングを制御できません

于 2008-09-23T16:14:45.430 に答える