Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assembly.GetCallingAssembly() and static constructors?

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?

like image 810
George Mauer Avatar asked Sep 23 '08 15:09

George Mauer


People also ask

What is static constructor?

A static constructor is used to initialize any static data, or to perform a particular action that needs to be performed only once. It is called automatically before the first instance is created or any static members are referenced.

Can static be applied to constructors?

Java constructor can not be static One of the important property of java constructor is that it can not be static. We know static keyword belongs to a class rather than the object of a class. A constructor is called when an object of a class is created, so no use of the static constructor.

Can static constructors use optional arguments?

Static constructors can use optional arguments. Overloaded constructors cannot use optional arguments. If we do not provide a constructor, then the compiler provides a zero-argument constructor.

Why static constructor is Parameterless in C#?

When a data member is shared among different instances it is imperative that data should be consistent among all the instances of the class. And also there is no way to call static constructor explicitly. Therefore the purpose of having a parameterized static constructor is useless.


3 Answers

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.

like image 84
Curt Hagenlocher Avatar answered Sep 23 '22 01:09

Curt Hagenlocher


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

like image 33
Harper Shelby Avatar answered Sep 23 '22 01:09

Harper Shelby


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;
}
like image 39
chilltemp Avatar answered Sep 21 '22 01:09

chilltemp