What is System.Void?

I've recently been taking an interest in the System.Void type. It's an illegal type to reference in C#, so why does it exist?

We regularly see the void keyword in C# as the result of a method which does not have a return value. When a method has a return type, it must push its result on the stack for its caller to pop. A method declared to return void, however, must not leave any result on the stack. An example follows

static void Test()
{
    A();
    int b = B();
}

static void A() { }
static int B() => 1;

The following code is the IL generated for the Test method (via ILDASM).

.method private hidebysig static void  Test() cil managed
{
// Code size       12 (0xc)
.maxstack  8
IL_0000:  call       void AbusingVoid.Program::A()
IL_0005:  call       int32 AbusingVoid.Program::B()
IL_000a:  pop
IL_000b:  ret
} // end of method Program::Test

We can see that the A() was not followed by a pop as opposed to B(). This demonstrates that void is implemented as a special case instead of a placeholder. A placeholder approach would require void methods to leave a value on the stack even if it is unused; in this case all method calls could be followed by a pop instruction without exception. The decision to special case this kind of method has had further impacts on the design decision, for example Action<T> could just be implemented as Func<T, Void> and Task could also be implemented as Task<Void>. Special casing System.Void has necessitated these redundant concepts and added complexity to code generation.

Why does System.Void even exist?

Reflection in .NET allows code to inspect method definitions. One can inspect the return types of such methods and instead of adding another special case for methods returning void, all methods can be represented by the System.Reflection.MethodInfo class. MethodInfo has a ReturnType property which is set to System.Void in the case of methods that have no return value.

static void A() { }

var aMethodInfo = typeof(Program).GetMethod("A", BindingFlags.Static | BindingFlags.NonPublic);
Console.WriteLine(aMethodInfo.AssemblyQualifiedName);
// Prints System.Void, System.Private.CoreLib [...]

What does it look like?

The class, defined in System.Private.CoreLib* is defined as follows (from GitHub).

namespace System
{
    // This class represents the void return type
    public struct Void
    {
    }
}

* Although the type appears to be defined in System.Private.CoreLib, through type forwarding (a magic I know little about) it also seems to be defined in System.Runtime.

So now we know System.Void is really just a placeholder for the purposes of reflection and instances of this type are never really created. Having said this... I want one! I want an instance of Void.

But I'll leave that for next time.


Other posts you might like


Join the Discussion

You must be signed in to comment.

No user information will be stored on our site until you comment.