First, if you want to know more about beforefieldinit , read John Skeet's article C # and beforefieldinit . Parts of this answer are based on this, and I will repeat the corresponding bits here.
Secondly, your code is very small, so the overhead will have a significant impact on your measurements. In real code, the impact will be much less.
Third, you do not need to use Reflection.Emit to determine if the class has a beforefieldint . You can disable this flag in C # by adding a static constructor (for example, static TestClassProxy() {} ).
Now what beforefieldinit does is that it determines when the type initializer (a method called .cctor ) is called. In terms of C #, the type of initializer contains all the static field initializers and the code from the static constructor, if any.
If you do not set this flag, the type initializer will be called when the class is instantiated or any of the static members of the class are created. (Taken from the C # specification, using the CLI specification here will be more accurate, but the end result will be the same. * )
This means that without beforefieldinit compiler is very limited when to call the type initializer, it cannot decide to name it a little earlier, even if it will be more convenient (and as a result faster code).
Knowing this, we can see what actually happens in your code. Static methods are problematic cases, because where a type initializer can be called. (The instance constructor is different, but you are not measuring it.)
I focused on the s_1_Test() method. And since I really don't need to do anything, I simplified it (to make the generated native code shorter):
public static object s_1_Test<T>(TestClass<pR> class1, pR local1) where T:IConvertible { return null; }
Now let's look at the disassembly in VS (in Release mode), first without a static constructor, that is, with beforefieldinit :
00000000 xor eax,eax 00000002 ret
Here the result is set to 0 (this is done in a somewhat confusing way for performance reasons ), and the method returns very simply.
What happens with a static static constructor (i.e. without beforefieldinit )?
00000000 sub rsp,28h 00000004 mov rdx,rcx 00000007 xor ecx,ecx 00000009 call 000000005F8213A0 0000000e xor eax,eax 00000010 add rsp,28h 00000014 ret
This is much more complicated, the real problem is the call statement, which apparently calls a function that, if necessary, starts the type initializer.
I consider this a source of performance difference between the two situations.
The reason why the added validation is necessary is because your type is generic and you use it with a reference type as a type parameter. In this case, the JIT code for the different generic versions of your class is common, but the type initializer must be called for each generic version. Transferring static methods to another, non-generic type would be one way to solve the problem.
* If you are not doing something crazy, like a method to call an instance on null using call (rather than callvirt , which throws for null ).