.NET Internals Cookbook Part 5 — Methods, parameters, modifiers

This is the fifth part of the .NET Internals Cookbook series. For your convenience you can find other parts in the table of contents in Part 0 – Table of contents

27. Can two methods differ in return type only?

Not in C#, but they can in IL. See this:

Interesting part is this:

The way you call the method determines what methods you can declare since we need to be able to distinguish them. Since in IL you specify the return type when calling the method, you can have two methods with different return types.

28. What is the difference between const and readonly?

See this code:

When you decompile it you get:

Const variable was replaced with raw integer, readonly variable was just used. This may have very unexpected consequences — if you change the value of the const variable and recompile the code, but not the user of this code, then the caller will still use old value.

29. How are arguments passed in C#? By value? By reference? Differently?

Passing by value is easy:


Here Foo(5) passed the value. The same goes for all value types, they are passed by value so they are copied when passed to a function. Because of that the variable a was not modified.

The same goes for references as well! You can often read that reference types are passed by, well, reference. But it is not true, see this code:


Even though reference was modified in the Foo method, the variable a is not modified. This is because what we pass is a reference, not an object. So reference types are passed in the same way as value types, only not the object is passed (or the value) but the reference to the object.

So to be super precise: references are passed by value but objects are passed by sharing.

C# can pass variables by reference as well:


When you execute it you can see that the variable a was modified.

30. In what order are method parameters calculated?

Most of the times this doesn’t matter but for named parameters this can be a little tricky:


Parameters are calculated in the order specified by the caller, not as specified in the function signature.

31. What is the difference between typeof and GetType?

The former is evaluated during compilation, the latter in runtime. This means that the former doesn’t need an object, as shown here:

Decompile and get this:

32. What is behind using and lock? Was it always compiled in this way?

A typical try+finally pattern, like here:

For using we get:

So in finally we check if the object is not null and then we call Dispose. It is important to notice that the object is created before the try block!

For locking w get this:

Again, object created before the try block.

Before C# 4 lock was using Monitor.Enter(object) method and was called before the try block which could result in a nasty, never released lock. Read more here.

33. What is the .NET calling convention?

For x86 it is clrcall convention which is like Fastcall but passes arguments from left to right.

Take this code:

It gives these calls:


For x64 it is Microsoft x64.

Code above gives:


34. Can you have const decimal? const string? const Foo?

Yes, see here:

However, there is a trick here. If you decompile the code, you get this:

Interesting parts are:

So you can see that the decimal is not a constant but readonly, it is initialized in the type constructor.

35. Can you pass a volatile variable by reference?

Yes and no. This code compiles:

But it shows warning that 'Program.a': a reference to a volatile field will not be treated as volatile.