Lior Ohana Lior Ohana - 1 month ago 16
C# Question

Managed C++ Static Constructor not called in .net4

I've recently moved a project I'm working on from .NET 3.5 to .NET 4. I'm using C#, Managed C++ and Unmanaged C++.

In one of my Managed C++ (interop) I'm having a static constructor:

public ref class StaticPool : public BaseStaticPools
{
public:
static StaticPool()
{
InitializePools();
}

static Poolable^ Dequeue()
{
return (Poolable^)Dequeue(Poolable::typeid);
}

private:
static void InitializePools()
{
BaseStaticPools::CreatePool(Poolable::typeid);
}
};


In .NET 3.5 once
Dequeue()
had been called for the first time it would trigger the static initialization, which runs the static constructor. Once I moved to .NET 4.0, the static constructor was never called.

I know there have been changes in static initializations in .NET 4.0, but according to all I read it should work fine.

Answer

In .NET, type initializers may only be called the first time a field is accessed. This is controlled by the [BeforeFieldInit] attribute.

I filed a bug report, which is only available to beta testers, despite being marked "Public".

Here's the explanation from Microsoft, which you may find helpful:

For C++, this is the intended behavior. We mark our classes with BeforeFieldInit, and so the initialization the CLR is performing is correct. We do not offer a way in C++/CLI to change this behavior. If you require the class constructor to run, you are able to call System.Runtime.CompilerServices.RuntimeHelpers::RunClassConstructor explicitly.


Since we're invoking the standard here, the line from Partition I, 8.9.5 says this:

If marked BeforeFieldInit then the type’s initializer method is executed at, or sometime before, first access to any static field defined for that type.

That section actually goes into detail about how a language implementation can choose to prevent the behavior you're describing. C++/CLI chooses not to, rather they allow the programmer to do so if they wish.

Basically, since the code below has absolutely no static fields, the JIT is completely correct in simply not invoking static class constructors.