C#idiomatic C#
declarationscsharp/language-reference/statements

Language

Declaration statements

Declaration statements introduce a new local variable, local constant, or local reference variable (ref local). Local variables can be explicitly or implicitly typed. A declaration statement can also include initialization of a variable's value.

  • page csharp/language-reference/statements/declarations
  • updated 01/16/2026

A declaration statement declares a new local variable, local constant, or local reference variable.


ms.custom: "updateeachrelease"

The C# language reference documents the most recently released version of the C# language. It also contains initial documentation for features in public previews for the upcoming language release.

The documentation identifies any feature first introduced in the last three versions of the language or in current public previews.

To declare a local variable, specify its type and provide its name. You can declare multiple variables of the same type in one statement, as the following example shows:

sample · csharpdocs/csharp/language-reference/statements/snippets/declarations/Declaration.csDeclare

csharp
namespace Declarations;

public static class Declaration
{
    public static void Examples()
    {
        {
            // <Declare>
            string greeting;
            int a, b, c;
            List<double> xs;
            // </Declare>
        }

        {
            // <DeclareAndInit>
            string greeting = "Hello";
            int a = 3, b = 2, c = a + b;
            List<double> xs = new();
            // </DeclareAndInit>
        }

        {
            // <LocalConstant>
            const string Greeting = "Hello";
            const double MinLimit = -10.0, MaxLimit = -MinLimit;
            // </LocalConstant>
        }
    }
}

In a declaration statement, you can also initialize a variable with its initial value:

sample · csharpdocs/csharp/language-reference/statements/snippets/declarations/Declaration.csDeclareAndInit

csharp
namespace Declarations;

public static class Declaration
{
    public static void Examples()
    {
        {
            // <Declare>
            string greeting;
            int a, b, c;
            List<double> xs;
            // </Declare>
        }

        {
            // <DeclareAndInit>
            string greeting = "Hello";
            int a = 3, b = 2, c = a + b;
            List<double> xs = new();
            // </DeclareAndInit>
        }

        {
            // <LocalConstant>
            const string Greeting = "Hello";
            const double MinLimit = -10.0, MaxLimit = -MinLimit;
            // </LocalConstant>
        }
    }
}

The preceding examples explicitly specify the type of a variable. You can also let the compiler infer the type of a variable from its initialization expression. To do that, use the var keyword instead of a type's name. For more information, see the Implicitly-typed local variables section.

To declare a local constant, use the const keyword, as the following example shows:

sample · csharpdocs/csharp/language-reference/statements/snippets/declarations/Declaration.csLocalConstant

csharp
namespace Declarations;

public static class Declaration
{
    public static void Examples()
    {
        {
            // <Declare>
            string greeting;
            int a, b, c;
            List<double> xs;
            // </Declare>
        }

        {
            // <DeclareAndInit>
            string greeting = "Hello";
            int a = 3, b = 2, c = a + b;
            List<double> xs = new();
            // </DeclareAndInit>
        }

        {
            // <LocalConstant>
            const string Greeting = "Hello";
            const double MinLimit = -10.0, MaxLimit = -MinLimit;
            // </LocalConstant>
        }
    }
}

When you declare a local constant, you must also initialize it.

For information about local reference variables, see the Reference variables section.

Implicitly typed local variables

When you declare a local variable, you can let the compiler infer the type of the variable from the initialization expression. To do that, use the var keyword instead of the name of a type:

sample · csharpdocs/csharp/language-reference/statements/snippets/declarations/ImplicitlyTyped.csImplicitlyTyped

csharp

namespace ImplicitTypes;

class Customer
{
    public string City { get; set; }
    public string Name { get; set; }
    public string Phone { get; set; }
}

public static class VarExample
{
    public static void ImplicitlyTyped()
    {
        // <ImplicitlyTyped>
        var greeting = "Hello";
        Console.WriteLine(greeting.GetType());  // output: System.String

        var a = 32;
        Console.WriteLine(a.GetType());  // output: System.Int32

        var xs = new List<double>();
        Console.WriteLine(xs.GetType());  // output: System.Collections.Generic.List`1[System.Double]
        // </ImplicitlyTyped>

        List<Customer> customers = new List<Customer>();
        //<VarExample>
        var fromPhoenix = from cust in customers
                          where cust.City == "Phoenix"
                          select new { cust.Name, cust.Phone };

        foreach (var customer in fromPhoenix)
        {
            Console.WriteLine($"Name={customer.Name}, Phone={customer.Phone}");
        }
        //</VarExample>
    }
}

As the preceding example shows, implicitly typed local variables are strongly typed.

A common use of var is with a constructor invocation expression. The use of var allows you to avoid repeating a type name in a variable declaration and object instantiation, as the following example shows:

csharp
var xs = new List<int>();

You can use a target-typed new expression as an alternative:

csharp
List<int> xs = new();
List<int>? ys = new();

When you work with anonymous types, you must use implicitly typed local variables. The following example shows a query expression that uses an anonymous type to hold a customer's name and phone number:

sample · csharpdocs/csharp/language-reference/statements/snippets/declarations/ImplicitlyTyped.csVarExample

csharp

namespace ImplicitTypes;

class Customer
{
    public string City { get; set; }
    public string Name { get; set; }
    public string Phone { get; set; }
}

public static class VarExample
{
    public static void ImplicitlyTyped()
    {
        // <ImplicitlyTyped>
        var greeting = "Hello";
        Console.WriteLine(greeting.GetType());  // output: System.String

        var a = 32;
        Console.WriteLine(a.GetType());  // output: System.Int32

        var xs = new List<double>();
        Console.WriteLine(xs.GetType());  // output: System.Collections.Generic.List`1[System.Double]
        // </ImplicitlyTyped>

        List<Customer> customers = new List<Customer>();
        //<VarExample>
        var fromPhoenix = from cust in customers
                          where cust.City == "Phoenix"
                          select new { cust.Name, cust.Phone };

        foreach (var customer in fromPhoenix)
        {
            Console.WriteLine($"Name={customer.Name}, Phone={customer.Phone}");
        }
        //</VarExample>
    }
}

In the preceding example, you can't explicitly specify the type of the fromPhoenix variable. The type is System.Collections.Generic.IEnumerable but in this case T is an anonymous type and you can't provide its name. That's why you need to use var. For the same reason, you must use var when you declare the customer iteration variable in the foreach statement.

For more information about implicitly typed local variables, see Implicitly-typed local variables.

In pattern matching, the var keyword is used in a var pattern.

Reference variables

When you declare a local variable and add the ref keyword before the variable's type, you declare a reference variable, or a ref local:

csharp
ref int aliasOfvariable = ref variable;

A reference variable is a variable that refers to another variable, which is called the referent. That is, a reference variable is an alias to its referent. When you assign a value to a reference variable, you assign that value to the referent. When you read the value of a reference variable, you return the referent's value. The following example demonstrates that behavior:

sample · csharpdocs/csharp/language-reference/statements/snippets/declarations/ReferenceVariables.csAliasToLocalVariable

csharp
public static class ReferenceVariables
{
    public static void Examples()
    {
        AliasToLocalVariable();
        RefReassign();
        RefReadonly();
    }

    private static void AliasToLocalVariable()
    {
        // <AliasToLocalVariable>
        int a = 1;
        ref int aliasOfa = ref a;
        Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})");  // output: (a, aliasOfa) is (1, 1)

        a = 2;
        Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})");  // output: (a, aliasOfa) is (2, 2)

        aliasOfa = 3;
        Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})");  // output: (a, aliasOfa) is (3, 3)
        // </AliasToLocalVariable>
    }

    private static void RefReassign()
    {
        // <RefReassign>
        void Display(int[] s) => Console.WriteLine(string.Join(" ", s));

        int[] xs = [0, 0, 0];
        Display(xs);

        ref int element = ref xs[0];
        element = 1;
        Display(xs);

        element = ref xs[^1];
        element = 3;
        Display(xs);
        // Output:
        // 0 0 0
        // 1 0 0
        // 1 0 3
        // </RefReassign>
    }

    private static void RefReadonly()
    {
        // <RefReadonly>
        int[] xs = [1, 2, 3];

        ref readonly int element = ref xs[0];
        // element = 100;  error CS0131: The left-hand side of an assignment must be a variable, property or indexer
        Console.WriteLine(element);  // output: 1

        element = ref xs[^1];
        Console.WriteLine(element);  // output: 3
        // </RefReadonly>
    }
}

Use the ref assignment operator = ref to change the referent of a reference variable, as the following example shows:

sample · csharpdocs/csharp/language-reference/statements/snippets/declarations/ReferenceVariables.csRefReassign

csharp
public static class ReferenceVariables
{
    public static void Examples()
    {
        AliasToLocalVariable();
        RefReassign();
        RefReadonly();
    }

    private static void AliasToLocalVariable()
    {
        // <AliasToLocalVariable>
        int a = 1;
        ref int aliasOfa = ref a;
        Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})");  // output: (a, aliasOfa) is (1, 1)

        a = 2;
        Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})");  // output: (a, aliasOfa) is (2, 2)

        aliasOfa = 3;
        Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})");  // output: (a, aliasOfa) is (3, 3)
        // </AliasToLocalVariable>
    }

    private static void RefReassign()
    {
        // <RefReassign>
        void Display(int[] s) => Console.WriteLine(string.Join(" ", s));

        int[] xs = [0, 0, 0];
        Display(xs);

        ref int element = ref xs[0];
        element = 1;
        Display(xs);

        element = ref xs[^1];
        element = 3;
        Display(xs);
        // Output:
        // 0 0 0
        // 1 0 0
        // 1 0 3
        // </RefReassign>
    }

    private static void RefReadonly()
    {
        // <RefReadonly>
        int[] xs = [1, 2, 3];

        ref readonly int element = ref xs[0];
        // element = 100;  error CS0131: The left-hand side of an assignment must be a variable, property or indexer
        Console.WriteLine(element);  // output: 1

        element = ref xs[^1];
        Console.WriteLine(element);  // output: 3
        // </RefReadonly>
    }
}

In the preceding example, the element reference variable is initialized as an alias to the first array element. Then it's ref reassigned to refer to the last array element.

You can define a ref readonly local variable. You can't assign a value to a ref readonly variable. However, you can ref reassign such a reference variable, as the following example shows:

sample · csharpdocs/csharp/language-reference/statements/snippets/declarations/ReferenceVariables.csRefReadonly

csharp
public static class ReferenceVariables
{
    public static void Examples()
    {
        AliasToLocalVariable();
        RefReassign();
        RefReadonly();
    }

    private static void AliasToLocalVariable()
    {
        // <AliasToLocalVariable>
        int a = 1;
        ref int aliasOfa = ref a;
        Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})");  // output: (a, aliasOfa) is (1, 1)

        a = 2;
        Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})");  // output: (a, aliasOfa) is (2, 2)

        aliasOfa = 3;
        Console.WriteLine($"(a, aliasOfa) is ({a}, {aliasOfa})");  // output: (a, aliasOfa) is (3, 3)
        // </AliasToLocalVariable>
    }

    private static void RefReassign()
    {
        // <RefReassign>
        void Display(int[] s) => Console.WriteLine(string.Join(" ", s));

        int[] xs = [0, 0, 0];
        Display(xs);

        ref int element = ref xs[0];
        element = 1;
        Display(xs);

        element = ref xs[^1];
        element = 3;
        Display(xs);
        // Output:
        // 0 0 0
        // 1 0 0
        // 1 0 3
        // </RefReassign>
    }

    private static void RefReadonly()
    {
        // <RefReadonly>
        int[] xs = [1, 2, 3];

        ref readonly int element = ref xs[0];
        // element = 100;  error CS0131: The left-hand side of an assignment must be a variable, property or indexer
        Console.WriteLine(element);  // output: 1

        element = ref xs[^1];
        Console.WriteLine(element);  // output: 3
        // </RefReadonly>
    }
}

You can assign a reference return to a reference variable, as the following example shows:

sample · csharpdocs/csharp/language-reference/statements/snippets/declarations/NumberStore.csReferenceReturns

csharp
namespace ReferenceReturns
{
    // <ReferenceReturns>
    using System;

    public class NumberStore
    {
        private readonly int[] numbers = [1, 30, 7, 1557, 381, 63, 1027, 2550, 511, 1023];

        public ref int GetReferenceToMax()
        {
            ref int max = ref numbers[0];
            for (int i = 1; i < numbers.Length; i++)
            {
                if (numbers[i] > max)
                {
                    max = ref numbers[i];
                }
            }
            return ref max;
        }

        public override string ToString() => string.Join(" ", numbers);
    }

    public static class ReferenceReturnExample
    {
        public static void Run()
        {
            var store = new NumberStore();
            Console.WriteLine($"Original sequence: {store.ToString()}");
            
            ref int max = ref store.GetReferenceToMax();
            max = 0;
            Console.WriteLine($"Updated sequence:  {store.ToString()}");
            // Output:
            // Original sequence: 1 30 7 1557 381 63 1027 2550 511 1023
            // Updated sequence:  1 30 7 1557 381 63 1027 0 511 1023
        }
    }
    // </ReferenceReturns>
}

In the preceding example, the GetReferenceToMax method is a returns-by-ref method. It doesn't return the maximum value itself, but a reference return that is an alias to the array element that holds the maximum value. The Run method assigns a reference return to the max reference variable. Then, by assigning to max, it updates the internal storage of the store instance. You can also define a ref readonly method. The callers of a ref readonly method can't assign a value to its reference return.

The iteration variable of the foreach statement can be a reference variable. For more information, see the foreach statement section of the Iteration statements article.

In performance-critical scenarios, the use of reference variables and returns might increase performance by avoiding potentially expensive copy operations.

The compiler ensures that a reference variable doesn't outlive its referent and stays valid for the whole of its lifetime. For more information, see the Ref safe contexts section of the C# language specification.

For information about the ref fields, see the ref fields section of the ref structure types article.

scoped ref

The contextual keyword scoped restricts the lifetime of a value. The scoped modifier restricts the ref-safe-to-escape or safe-to-escape lifetime, respectively, to the current method. By adding the scoped modifier, you assert that your code doesn't extend the lifetime of the variable.

Apply scoped to a parameter or local variable. You can apply the scoped modifier to parameters and locals when the type is a ref struct. Otherwise, apply the scoped modifier only to local reference variables. That rule includes local variables declared with the ref modifier and parameters declared with the in, ref, or out modifiers.

The scoped modifier is implicitly added to this in methods declared in a struct, out parameters, and ref parameters when the type is a ref struct.

C# language specification

For more information, see the following sections of the C# language specification:

For more information about the scoped modifier, see The scoped modifier in the C# language specification.

See also