C# – Assembly.GetCallingAssembly() and static constructors

c++reflectionstatic-constructor

Ok, so I just ran into the following problem that raised an eyebrow.

For various reasons I have a testing setup where Testing classes in a TestingAssembly.dll depend on the TestingBase class in a BaseTestingAssembly.dll.
One of the things the TestBase does in the meantime is look for a certain embedded resource in its own and the calling assembly

So my BaseTestingAssembly contained the following lines…

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

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

Static since I figured, these assemblies would be the same over the application's lifetime so why bother recalculating them on every single test.

When running this however I noticed that both _assembly and _calling_assembly were being set to BaseTestingAssembly rather than BaseTestingAssembly and TestingAssembly respectively.

Setting the variables to non-static and having them initialized in a regular constructor fixed this but I am confused why this happened to begin this. I thought static constructors run the first time a static member gets referenced. This could only have been from my TestingAssembly which should then have been the caller. Does anyone know what might have happened?

Best Solution

The static constructor is called by the runtime and not directly by user code. You can see this by setting a breakpoint in the constructor and then running in the debugger. The function immediately above it in the call chain is native code.

Edit: There are a lot of ways in which static initializers run in a different environment than other user code. Some other ways are

  1. They're implicitly protected against race conditions resulting from multithreading
  2. You can't catch exceptions from outside the initializer

In general, it's probably best not to use them for anything too sophisticated. You can implement single-init with the following pattern:

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

Add locking if you expect multithreaded access.