Getting started with C# LanguageVerbatim StringsOperatorsExtension MethodsCollection InitializersString InterpolationC# 6.0 FeaturesConstructors and FinalizersKeywordsGenericsReflectionInheritanceNull-Coalescing OperatorUsing StatementString Escape SequencesException HandlingNull-conditional OperatorsBuilt-in TypesLambda expressionsAsync-AwaitPropertiesThreadingUsing DirectiveMethodsYield KeywordEventsLINQ QueriesCommon String OperationsExpression TreesOverload ResolutionString.Formatnameof OperatorUnsafe Code in .NETInitializing PropertiesBindingList<T>ILGeneratorObject initializersXML Documentation CommentsPreprocessor directivesDynamic typeAnonymous typesStructsTuplesEnumAccess ModifiersTask Parallel LibraryAttributesGuidSingleton ImplementationDelegatesNullable typesGarbage Collector in .NetNetworkingArraysEquality OperatorLock StatementAction FiltersXmlDocument and the System.Xml namespaceDateTime MethodsBackgroundWorkerPolymorphismStatic ClassesIndexerIDisposable interfaceAliases of built-in typesImmutabilityXDocument and the System.Xml.Linq namespaceC# 7.0 FeaturesPerforming HTTP requestsGenerating Random Numbers in C#LoopingNamed ArgumentsDiagnosticsInterfacesIEnumerableNaming ConventionsAn overview of c# collectionsChecked and UncheckedRecursionFunctional ProgrammingLiteralsCastingNullReferenceExceptionFunc delegatesLINQ to XMLHash FunctionsHandling FormatException when converting string to other typesCryptography (System.Security.Cryptography)INotifyPropertyChanged interfaceValue type vs Reference typeC# 4.0 FeaturesIQueryable interfaceTask Parallel Library (TPL) Dataflow ConstructsStreamRuntime CompileConditional StatementsInteroperabilityOverflowEquals and GetHashCodeType ConversionParallel LINQ (PLINQ)String ManipulationString ConcatenatePartial class and methodsStopwatchesRegex ParsingC# ScriptC# 3.0 FeaturesAsync/await, Backgroundworker, Task and Thread ExamplesTimersFunction with multiple return valuesBinary SerializationMaking a variable thread safeIComparableCode ContractsIteratorsAssemblyInfo.cs ExamplesFile and Stream I/OCode Contracts and AssertionsCachingC# 5.0 FeaturesImplementing Flyweight Design PatternStringBuilderImplementing Decorator Design PatternAccessing DatabasesT4 Code GenerationMicrosoft.Exchange.WebServices.NET Compiler Platform (Roslyn)Data AnnotationUsing SQLite in C#System.Management.AutomationFileSystemWatcherSystem.DirectoryServices.Protocols.LdapConnectionNamed and Optional ArgumentsComments and regionsC# Authentication handlerPointers & Unsafe CodePointersHow to use C# Structs to create a Union type (Similar to C Unions)BigIntegerDependency InjectionReactive Extensions (Rx)Creational Design PatternsCreating a Console Application using a Plain-Text Editor and the C# Compiler (csc.exe)Reading and writing .zip filesGeneric Lambda Query BuilderImport Google ContactsLambda ExpressionsCLSCompliantAttributeObservableCollection<T>Synchronization Context in Async-AwaitICloneableRead & Understand StacktracesLinq to ObjectsASP.NET IdentityAccess network shared folder with username and passwordAsynchronous SocketStructural Design PatternsO(n) Algorithm for circular rotation of an arrayCreating Own MessageBox in Windows Form ApplicationIncluding Font ResourcesObject Oriented Programming In C#Using json.netGetting Started: Json with C#Windows Communication Foundation

Null-conditional Operators

Other topics

Remarks:

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

Null-Conditional Operator

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

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

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

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

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

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.

Syntax:

  • 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();

Contributors

Topic Id: 41

Example Ids: 173,174,699,14832

This site is not affiliated with any of the contributors.