Member access operators (C# reference)

You might use the following operators when you access a type member:

Member access operator .

You use the . token to access a member of a namespace or a type, as the following examples demonstrate:

  • Use . to access a nested namespace within a namespace, as the following example of a using directive shows:

    using System.Collections.Generic;
    
  • Use . to form a qualified name to access a type within a namespace, as the following code shows:

    System.Collections.Generic.IEnumerable<int> numbers = new int[] { 1, 2, 3 };
    

    Use a using directive to make the use of qualified names optional.

  • Use . to access type members, static and non-static, as the following code shows:

    var constants = new List<double>();
    constants.Add(Math.PI);
    constants.Add(Math.E);
    Console.WriteLine($"{constants.Count} values to show:");
    Console.WriteLine(string.Join(", ", constants));
    // Output:
    // 2 values to show:
    // 3.14159265358979, 2.71828182845905
    

You can also use . to access an extension method.

Indexer operator []

Square brackets, [], are typically used for array, indexer, or pointer element access.

Array access

The following example demonstrates how to access array elements:

int[] fib = new int[10];
fib[0] = fib[1] = 1;
for (int i = 2; i < fib.Length; i++)
{
    fib[i] = fib[i - 1] + fib[i - 2];
}
Console.WriteLine(fib[fib.Length - 1]);  // output: 55

double[,] matrix = new double[2,2];
matrix[0,0] = 1.0;
matrix[0,1] = 2.0;
matrix[1,0] = matrix[1,1] = 3.0;
var determinant = matrix[0,0] * matrix[1,1] - matrix[1,0] * matrix[0,1];
Console.WriteLine(determinant);  // output: -3

If an array index is outside the bounds of the corresponding dimension of an array, an IndexOutOfRangeException is thrown.

As the preceding example shows, you also use square brackets when you declare an array type or instantiate an array instance.

For more information about arrays, see Arrays.

Indexer access

The following example uses .NET Dictionary<TKey,TValue> type to demonstrate indexer access:

var dict = new Dictionary<string, double>();
dict["one"] = 1;
dict["pi"] = Math.PI;
Console.WriteLine(dict["one"] + dict["pi"]);  // output: 4.14159265358979

Indexers allow you to index instances of a user-defined type in the similar way as array indexing. Unlike array indices, which must be integer, the indexer arguments can be declared to be of any type.

For more information about indexers, see Indexers.

Other usages of []

For information about pointer element access, see the Pointer element access operator [] section of the Pointer related operators article.

You also use square brackets to specify attributes:

[System.Diagnostics.Conditional("DEBUG")]
void TraceMethod() {}

Null-conditional operators ?. and ?[]

Available in C# 6 and later, a null-conditional operator applies a member access, ?., or element access, ?[], operation to its operand only if that operand evaluates to non-null. If the operand evaluates to null, the result of applying the operator is null. The null-conditional member access operator ?. is also known as the Elvis operator.

The null-conditional operators are short-circuiting. That is, if one operation in a chain of conditional member or element access operations returns null, the rest of the chain doesn't execute. In the following example, B is not evaluated if A evaluates to null and C is not evaluated if A or B evaluates to null:

A?.B?.Do(C);
A?.B?[C];

The following example demonstrates the usage of the ?. and ?[] operators:

double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
{
    return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
}

var sum1 = SumNumbers(null, 0);
Console.WriteLine(sum1);  // output: NaN

var numberSets = new List<double[]>
{
    new[] { 1.0, 2.0, 3.0 },
    null
};

var sum2 = SumNumbers(numberSets, 0);
Console.WriteLine(sum2);  // output: 6

var sum3 = SumNumbers(numberSets, 1);
Console.WriteLine(sum3);  // output: NaN

The preceding example also shows the usage of the null-coalescing operator. You might use the null-coalescing operator to provide an alternative expression to evaluate in case the result of the null-conditional operation is null.

Thread-safe delegate invocation

Use the ?. operator to check if a delegate is non-null and invoke it in a thread-safe way (for example, when you raise an event), as the following code shows:

PropertyChanged?.Invoke(…)

That code is equivalent to the following code that you would use in C# 5 or earlier:

var handler = this.PropertyChanged;
if (handler != null)
{
    handler(…);
}

Invocation operator ()

Use parentheses, (), to call a method or invoke a delegate.

The following example demonstrates how to call a method, with or without arguments, and invoke a delegate:

Action<int> display = s => Console.WriteLine(s);

var numbers = new List<int>();
numbers.Add(10);
numbers.Add(17);
display(numbers.Count);   // output: 2

numbers.Clear();
display(numbers.Count);   // output: 0

You also use parentheses when you invoke a constructor with the new operator.

Other usages of ()

You also use parentheses to specify the order in which to evaluate operations in an expression. For more information, see the Adding parentheses section of the Operators article. For the list of operators ordered by precedence level, see C# operators.

Cast expressions, which perform explicit type conversions, also use parentheses.

Operator overloadability

The . and () operators cannot be overloaded. The [] operator is also considered a non-overloadable operator. Use indexers to support indexing with user-defined types.

C# language specification

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

See also