Here's a rundown of the two primary types in C#: Value and Reference; along with notes on how to make each nullable. Pointers are a 3rd type category mentioned in C# documentation which I won't review.


What are they?

  • A data type is a value type if it holds the data within its own memory allocation.

  • There are two main categories:
    (a) Structs
    (b) Enumerations (Every enumeration type has an underlying type, which can be any integral type except char.)

  • Structs fall into 3 categories:
    (a) Numeric types (Integral types like char, short, int, long, etc; Floating-point types like float and double; and decimal)
    (b) bool
    (c) User defined structs.

  • Structs are cut-down classes which don’t support inheritance or finalizers.

  • Structs are defined the same way as classes except you use struct as the keyword.

Do they support inheritance?

  • Value types do not support inheritance. They are represented in memory as a block of bytes without any more information and thus don't have room for a pointer which can refer to other objects.

  • Unlike reference types, you cannot derive a new type from a value type. However, like reference types, structs can implement interfaces.

How are they stored?

  • Value types directly store data in a single space in memory. When the runtime deals with a value type, it's dealing directly with its underlying data and this can be very efficient, particularly with primitive types.

How is garbage collection handled?

  • Value types may live on the stack, in which case their memory is reclaimed when a method exits and the stack pointer is adjusted.

  • Value types may also live on the heap as fields of reference types. In that case, the memory is reclaimed when the reference-type object is collected by the garbage collector.

  • The stack is a simple first-in last-out memory structure, and is highly efficient. When a method is invoked, the CLR bookmarks the top of the stack. The method then pushes data onto the stack as it executes. When the method completes, the CLR just resets the stack to its previous bookmark—“popping” all the method’s memory allocations is one simple operation.

What is the Value Type class inheritance heirarchy?

  • Structs inherit: System.Object > System.ValueType

  • Enums heirarchy: System.Object > System.ValueType > System.Enum

Are Value Types nullable?

  • A value type cannot contain a nullable value by default.

  • You can make a value type nullable, by using Nullable struct which is a wrapper over a value type T exposing two properties HasValue and Value.

  • A nullable type can represent the correct range of values for its underlying value type, plus an additional null value.

  • T? is shorthand for Nullable; for example, int? is the same as Nullable


What are they?

  • The following keywords are used to declare reference types:
    (a) class
    (b) interface
    (c) delegate

  • C# also provides the following built-in reference types:
    (a) dynamic
    (b) object
    (c) string

Do they support inheritance?

  • Reference types support inheritance.

  • Instances of class types are pointers and can then refer to the things you need for inheritance.

How are they stored?

  • An object is created in memory and then handled through a separate reference like a pointer.

How is garbage collection handled?

  • .NET objects are allocated in a memory called managed heap, where they will be automatically destroyed by the garbage collector.

  • The heap can be pictured as a random jumble of objects. Its advantage is that it allows objects to be allocated or deallocated in a random order. The heap requires the overhead of a memory manager and garbage collector to keep things in order.

  • Once a class is defined, you can allocate any number of objects using the C# new keyword.

  • The new keyword returns a reference to the object on the heap, not the actual object itself. This reference variable is stored on the stack for further use in your application.

Are Value Types nullable?

  • Reference types have support for null by default; thus you can't create a nullable type based on a reference type.

Note: I used a number of sources when gathering this information.