views:

794

answers:

3

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?

+1  A: 

I think the answer is here in the discussion of C# static constructors. My best guess is that the static constructor is getting called from an unexpected context because:

The user has no control on when the static constructor is executed in the program

Harper Shelby
Actually you have some control :)
leppie
+3  A: 

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.

Curt Hagenlocher
so why is the calling assembly not null then?
George Mauer
Would that be more useful? :)
Curt Hagenlocher
No, it just seems like that would make sense though
George Mauer
+1  A: 

Assembly.GetCallingAssembly() simply returns the assembly of the second entry in the call stack. That can very depending upon where how your method/getter/constructor is called. Here is what I did in a library to get the assembly of the first method that is not in my library. (This even works in static constructors.)

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