C Sharp TutorialC Sharp .NET Compiler Platform (Roslyn)C Sharp 3.0 FeaturesC Sharp 4.0 FeaturesC Sharp 5.0 FeaturesC Sharp 6.0 FeaturesC Sharp 7.0 FeaturesC Sharp Access ModifiersC Sharp Access network shared folder with username and passwordC Sharp Accessing DatabasesC Sharp Action FiltersC Sharp Aliases of built-in typesC Sharp an overview of collectionsC Sharp Anonymous typesC Sharp ArraysC Sharp ASP.NET IdentityC Sharp AssemblyInfo.cs ExamplesC Sharp Async-AwaitC Sharp Async/await, Backgroundworker, Task and Thread ExamplesC Sharp Asynchronous SocketC Sharp AttributesC Sharp Authentication handlerC Sharp BackgroundWorkerC Sharp BigIntegerC Sharp Binary SerializationC Sharp BindingListC Sharp Built-in TypesC Sharp CachingC Sharp CastingC Sharp Checked and UncheckedC Sharp CLSCompliantAttributeC Sharp Code ContractsC Sharp Code Contracts and AssertionsC Sharp Collection InitializersC Sharp Comments and regionsC Sharp Common String OperationsC Sharp Conditional StatementsC Sharp Constructors and FinalizersC Sharp Creating Own MessageBox in Windows Form ApplicationC Sharp Creational Design PatternsC Sharp Cryptography (System.Security.Cryptography)C Sharp Data AnnotationC Sharp DateTime MethodsC Sharp DelegatesC Sharp Dependency InjectionC Sharp DiagnosticsC Sharp Dynamic typeC Sharp EnumC Sharp Equality OperatorC Sharp Equals and GetHashCodeC Sharp EventsC Sharp Exception HandlingC Sharp Expression TreesC Sharp Extension MethodsC Sharp File and Stream I/OC Sharp FileSystemWatcherC Sharp Func delegatesC Sharp Function with multiple return valuesC Sharp Functional ProgrammingC Sharp Garbage Collector in .NETC Sharp Generating Random NumbersC Sharp Generic Lambda Query BuilderC Sharp GenericsC Sharp Getting Started: Json with C SharpC Sharp GuidC Sharp Handling FormatException when converting string to other typesC Sharp Hash FunctionsC Sharp ICloneableC Sharp IComparableC Sharp IDisposable interfaceC Sharp IEnumerableC Sharp ILGeneratorC Sharp ImmutabilityC Sharp Implementing Decorator Design PatternC Sharp Implementing Flyweight Design PatternC Sharp Import Google ContactsC Sharp Including Font ResourcesC Sharp IndexerC Sharp InheritanceC Sharp Initializing PropertiesC Sharp INotifyPropertyChanged interfaceC Sharp InterfacesC Sharp InteroperabilityC Sharp IQueryable interfaceC Sharp IteratorsC Sharp KeywordsC Sharp Lambda expressionsC Sharp Lambda ExpressionsC Sharp LINQ QueriesC Sharp LINQ to Objects

C Sharp Null-conditional Operators

From WikiOD

Syntax[edit | edit source]

  • X?.Y; //null if X is null else X.Y
  • X?.Y?.Z; //null if X is null or Y is null else X.Y.Z
  • X?[index]; //null if X is null else X[index]
  • X?.ValueMethod(); //null if X is null else the result of X.ValueMethod();
  • X?.VoidMethod(); //do nothing if X is null else call X.VoidMethod();

Remarks[edit | edit source]

Note that when using the null coalescing operator on a value type T you will get a Nullable<T> back.

Null-Conditional Operator[edit | edit source]

The ?. operator is syntactic sugar to avoid verbose null checks. It's also known as the Safe navigation operator.

Class used in the following example:

public class Person
    public int Age { get; set; }
    public string Name { get; set; }
    public Person Spouse { get; set; }

If an object is potentially null (such as a function that returns a reference type) the object must first be checked for null to prevent a possible NullReferenceException. Without the null-conditional operator, this would look like:

Person person = GetPerson();

int? age = null;
if (person != null)
    age = person.Age;

The same example using the null-conditional operator:

Person person = GetPerson();

var age = person?.Age;    // 'age' will be of type 'int?', even if 'person' is not null

Chaining the Operator[edit | edit source]

The null-conditional operator can be combined on the members and sub-members of an object.

// Will be null if either `person` or `person.Spouse` are null
int? spouseAge = person?.Spouse?.Age;

Combining with the Null-Coalescing Operator[edit | edit source]

The null-conditional operator can be combined with the null-coalescing operator to provide a default value:

// spouseDisplayName will be "N/A" if person, Spouse, or Name is null
var spouseDisplayName = person?.Spouse?.Name ?? "N/A";

The Null-Conditional Index[edit | edit source]

Similarly to the ?. operator, the null-conditional index operator checks for null values when indexing into a collection that may be null.

string item = collection?[index];

is syntactic sugar for

string item = null;
if(collection != null)
    item = collection[index];

Avoiding NullReferenceExceptions[edit | edit source]

var person = new Person
    Address = null;

var city = person.Address.City; //throws a NullReferenceException
var nullableCity = person.Address?.City; //returns the value of null

This effect can be chained together:

var person = new Person
    Address = new Address
        State = new State
            Country = null

// this will always return a value of at least "null" to be stored instead
// of throwing a NullReferenceException
var countryName = person?.Address?.State?.Country?.Name;

Null-conditional Operator can be used with Extension Method[edit | edit source]

Extension Method can work on null references, but you can use ?. to null-check anyway.

public class Person 
    public string Name {get; set;}

public static class PersonExtensions
    public static int GetNameLength(this Person person)
        return person == null ? -1 : person.Name.Length;

Normally, the method will be triggered for null references, and return -1:

Person person = null;
int nameLength = person.GetNameLength(); // returns -1

Using ?. the method will not be triggered for null references, and the type is int?:

Person person = null;
int? nameLength = person?.GetNameLength(); // nameLength is null.

This behavior is actually expected from the way in which the ?. operator works: it will avoid making instance method calls for null instances, in order to avoid NullReferenceExceptions. However, the same logic applies to the extension method, despite the difference on how the method is declared.

For more information on why the extension method is called in the first example, please see the Extension methods - null checking documentation.