Frage

Ok, so dass ich nur in das folgende Problem laufe, die eine Augenbraue hoch.

Aus verschiedenen Gründen habe ich einen Test-Setup, wo Testing Klassen in einem TestingAssembly.dll hängen von der TestingBase Klasse in einem BaseTestingAssembly.dll. Eines der Dinge, die Testbase in der Zwischenzeit tut, ist sucht eine bestimmte eingebettete Ressource in ihrer eigenen und der anrufende Montage

Also meine BaseTestingAssembly enthielt die folgenden Zeilen ...

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

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

Static, da ich dachte, diese Baugruppen die gleiche über die Anwendung des Lebens sein würde warum soll man sie auf jedem einzelnen Test neu berechnet wird.

Wenn diese laufen jedoch bemerkte ich, dass beide _assembly und _calling_assembly wurden BaseTestingAssembly gesetzt wird, anstatt BaseTestingAssembly und TestingAssembly sind.

Einstellen der Variablen nicht statisch und haben sie in einem regulären Konstruktor fixiert diese initialisiert, aber ich bin verwirrt, warum dies dies beginnen geschah. Ich dachte, statische Konstruktoren das erste Mal, wenn ein statisches Element ausgefuehrt wird verwiesen. Dies konnte nur von meinem TestingAssembly gewesen, die dann der Anrufer hätte sein sollen. Wer weiß, was passiert sein könnte?

War es hilfreich?

Lösung

Der statische Konstruktor wird von der Laufzeit und nicht direkt von Benutzercode genannt. Sie können sehen, durch einen Haltepunkt im Konstruktor festlegen und dann in dem Debugger ausgeführt wird. Die Funktion unmittelbar darüber in der Aufrufkette ist nativen Code.

Edit: Es gibt viele Möglichkeiten, in denen statische Initialisierer in einer anderen Umgebung ausgeführt werden als andere Benutzercode. Einige andere Wege gibt,

  1. Sie sind implizit geschützt gegen Rennbedingungen aus Multithreading
  2. Sie können keine Ausnahmen von außerhalb des initializer fangen

Im Allgemeinen ist es wahrscheinlich am besten, sie nicht für etwas zu verwenden, zu anspruchsvoll. Sie können mit dem folgenden Muster Single-init implementieren:

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;
  }
}

Fügen Sie Sperren, wenn Sie Multi-Thread-Zugang erwarten.

Andere Tipps

Ich denke, die Antwort ist hier in der Diskussion über C # statische Konstruktoren . Meine beste Vermutung ist, dass der statische Konstruktor wird von einem unerwarteten Kontext genannt zu werden, weil:

  

Der Benutzer hat keine Kontrolle über, wenn die   statischer Konstruktor wird in dem ausgeführten   Programm

Assembly.GetCallingAssembly () gibt einfach die Montage des zweiten Eintrag in der Aufrufliste. Das kann sehr abhängig davon, wo, wie Sie Ihre Methode / Getter / Konstruktor aufgerufen wird. Hier ist, was ich in einer Bibliothek hat die Montage des ersten Verfahrens zu erhalten, die nicht in meiner Bibliothek ist. (Dies funktioniert auch bei statischen Konstruktoren.)

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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top