Variables and Parameters

A variable represents a storage location that has a modifiable value. A variable can be a local variable, parameter (value, ref, or out), field (instance or static), or array element.

The stack and the heap are the places where variables and constants reside. Each has very different lifetime semantics.

C# enforces a definite assignment policy. In practice, this means that outside of an unsafe context, it’s impossible to access uninitialized memory. Definite assignment has three implications:

For example, the following code results in a compile-time error:

static void Main()
{
  int x;
  Console.WriteLine (x);        // Compile-time error
}

However, if x were instead a field of the containing class, this would be legal and would print 0.

All type instances have a default value. The default value for the predefined types is the result of a bitwise zeroing of memory, and is null for reference types, 0 for numeric and enum types, '\0' for the char type, and false for the bool type.

You can obtain the default value for any type using the default keyword (in practice, this is useful with generics, as we’ll see later). The default value in a custom value type (i.e., struct) is the same as the default value for each field defined by the custom type.

A method has a sequence of parameters. Parameters define the set of arguments that must be provided for that method. In this example, the method Foo has a single parameter named p, of type int:

static void Foo (int p)   // p is a parameter
{
  ...
}
static void Main() { Foo (8); }   // 8 is an argument

You can control how parameters are passed with the ref and out modifiers:

Parameter modifier

Passed by

Variable must be definitely assigned

None

Value

Going in

Ref

Reference

Going in

out

Reference

Going out

From C# 4.0, methods, constructors, and indexers can declare optional parameters. A parameter is optional if it specifies a default value in its declaration:

void Foo (int x = 23) { Console.WriteLine (x); }

Optional parameters may be omitted when calling the method:

Foo();     // 23

The default argument of 23 is actually passed to the optional parameter x—the compiler bakes the value 23 into the compiled code at the calling side. The preceding call to Foo is semantically identical to:

Foo (23);

because the compiler simply substitutes the default value of an optional parameter wherever it is used.

Warning

Adding an optional parameter to a public method that’s called from another assembly requires recompilation of both assemblies—just as though the parameter were mandatory.

The default value of an optional parameter must be specified by a constant expression, or a parameterless constructor of a value type. Optional parameters cannot be marked with ref or out.

Mandatory parameters must occur before optional parameters in both the method declaration and method call (the exception is with params arguments, which still always come last). In the following example, the explicit value of 1 is passed to x, and the default value of 0 is passed to y:

void Foo (int x = 0, int y = 0)
{
  Console.WriteLine (x + ", " + y);
}
void Test()
{
  Foo(1);    // 1, 0
}

To do the converse (pass a default value to x and an explicit value to y) you must combine optional parameters with named arguments.

It is often the case that you declare and initialize a variable in one step. If the compiler is able to infer the type from the initialization expression, you can use the word var in place of the type declaration. For example:

var x = "hello";
var y = new System.Text.StringBuilder();
var z = (float)Math.PI;

This is precisely equivalent to:

string x = "hello";
System.Text.StringBuilder y =
  new System.Text.StringBuilder();
float z = (float)Math.PI;

Because of this direct equivalence, implicitly typed variables are statically typed. For example, the following generates a compile-time error:

var x = 5;
x = "hello";    // Compile-time error; x is of type int

In the section Anonymous Types, we describe a scenario where the use of var is mandatory.