537

With C# 6.0 in the VS2015 preview we have a new operator, ?., which can be used like this:

public class A {
   string PropertyOfA { get; set; }
}

...

var a = new A();
var foo = "bar";
if(a?.PropertyOfA != foo) {
   //somecode
}

What exactly does it do?

Marcos Dimitrio
  • 6,651
  • 5
  • 38
  • 62
Arkadiusz Kałkus
  • 17,101
  • 19
  • 69
  • 108

3 Answers3

743

It's the null conditional operator. It basically means:

"Evaluate the first operand; if that's null, stop, with a result of null. Otherwise, evaluate the second operand (as a member access of the first operand)."

In your example, the point is that if a is null, then a?.PropertyOfA will evaluate to null rather than throwing an exception - it will then compare that null reference with foo (using string's == overload), find they're not equal and execution will go into the body of the if statement.

In other words, it's like this:

string bar = (a == null ? null : a.PropertyOfA);
if (bar != foo)
{
    ...
}

... except that a is only evaluated once.

Note that this can change the type of the expression, too. For example, consider FileInfo.Length. That's a property of type long, but if you use it with the null conditional operator, you end up with an expression of type long?:

FileInfo fi = ...; // fi could be null
long? length = fi?.Length; // If fi is null, length will be null
John Cummings
  • 1,949
  • 3
  • 22
  • 38
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    @SLaks: I thought it was "conditional null" but I could be wrong. Last time I checked the Roslyn language features docs, it hadn't been renamed to either. Maybe the source is the authority here - will check. – Jon Skeet Feb 05 '15 at 19:16
  • "conditional null" makes it sound like it's a kind of null, which it isn't. – SLaks Feb 05 '15 at 19:19
  • 3
    @SLaks: Sure. In SyntaxKind it's apparently ConditionalAccessExpression which is annoyingly neither of them... – Jon Skeet Feb 05 '15 at 19:19
  • @SLaks: Have asked Pilchie :) – Jon Skeet Feb 05 '15 at 19:29
  • If the OP's example `if(a ?. PropertyOfA != foo)` is valid then your answer implies that `if(null)` is also valid. Is it, and if so, does it evaluate to `true` or `false`? – 500 - Internal Server Error Feb 05 '15 at 20:41
  • @500-InternalServerError: No, it's only the `a?.PropertyOfA` that evaluates to null - I'll make that clear. – Jon Skeet Feb 05 '15 at 20:43
  • 23
    i preferred the name "Elvis" operator :P – Ahmed ilyas Feb 05 '15 at 20:44
  • 3
    Just for the record I've seen five different names for this operator: safe navigation, null-conditional, null propagation, conditional access, Elvis. – Gigi Feb 08 '15 at 18:57
  • Even on the highest warning level, with warnings as error, the Microsoft compiler will allow the "unsafe" code. Mono on the other hand will throw an error and call for an explicit cast. This is just a hint for everyone getting `CS0019` in Mono on code that compiles fine with .NET. – turbo Mar 07 '16 at 18:51
  • @mınxomaτ: Which "unsafe" code are you talking about? – Jon Skeet Mar 07 '16 at 19:10
  • @JonSkeet Not really unsafe (hence the quotemarks). It's about your note about suddenly changing types. Mono users frequently encounter error messages such as `Cannot implicitly convert type 'bool?' to 'bool'.` when building code that contains `?.` No such error is generated with .NET's compiler (which is not a problem). – turbo Mar 07 '16 at 19:15
  • Old question, but this doesn't warrant its own: Is there a way to use this for a case like `string.Join(",", potentiallyNull)`, or should I just stick to using the ternary operator? – Sinjai Jul 19 '17 at 18:00
  • @Sinjai maybe `potentiallyNull ?? ""` – Gabriel Oct 09 '17 at 18:59
  • @Gabriel Yeah but what about when it's not null. Then I want to do the `string.Join()` function. I don't see a way around ternary, I was just wondering if there was someone more clever than myself who knew some sort of magic. – Sinjai Oct 09 '17 at 19:04
  • 1
    If you do `string.Join(",", potentiallyNull ?? "")` and `potentiallyNull` is null, then `string.Join` returns an empty string. Isn't this what you want? – Gabriel Oct 09 '17 at 19:09
  • I think "safe evaluation" would be the best to describe this operator. It makes sure you don't evaluate properties or methods of a null object because then you get all those nasty errors. The bad is that "it hides" the problem why the Object is null because mostly it was not intended to be null. So it should be used with that in mind. – Herman Van Der Blom Nov 16 '17 at 13:07
  • @HermanVanDerBlom: Well an *object* is never null to start with... I'd be happy with "null-safe dereferencing" but "safe evaluation" sounds a bit too broad to me. I think it's best to stick to the language specification terminology though: the null conditional operator. – Jon Skeet Nov 16 '17 at 13:10
  • The expression object?.x is safe evaluated because it does not throws a error because object does not have a value. With an object is null I meant the object is declared but does not have a value. – Herman Van Der Blom Nov 16 '17 at 13:29
  • @HermanVanDerBlom: Again, that terminology is incorrect - it's the *variable* that's declared, and the variable has a value of null. But consider `x?.Foo(10)` - is that "safe evaluation"? Sure, it won't throw a null reference exception immediately if `x` is null, but it could easily still throw an exception. It could even throw a NullReferenceException, inside `Foo`. It's only the dereferencing of x that's null-safe, hence my suggested terminology if you really, really don't want to use what the C# team has decided on. – Jon Skeet Nov 16 '17 at 13:31
  • 1
    Ok for my purpose I consider the whole expression as "safe evaluation" and I know only the x? part plays a role in this. The "safe" is because its done at run-time. The Foo(10) part is not interesting to me because I already made sure that works at compile-time. – Herman Van Der Blom Nov 16 '17 at 13:43
  • 1
    @HermanVanDerBlom: I think we'll have to agree to disagree. I definitely don't think "safe evaluation" is as clear and precise as either "null-safe dereferencing" or "the null conditional operator". – Jon Skeet Nov 16 '17 at 13:44
  • It‘s simply syntactic sugar for binding field / property access or a method call as a function to its left hand side argument, interpreting that as a monoid in a category of endofunctors. – yeoman Feb 28 '18 at 23:30
  • 3
    Useful to note... you can also use the null conditional on arrays, like: a?[x] – KevinVictor Apr 14 '20 at 16:15
136

It can be very useful when flattening a hierarchy and/or mapping objects. Instead of:

if (Model.Model2 == null
  || Model.Model2.Model3 == null
  || Model.Model2.Model3.Model4 == null
  || Model.Model2.Model3.Model4.Name == null)
{
  mapped.Name = "N/A"
}
else
{
  mapped.Name = Model.Model2.Model3.Model4.Name;
}

It can be written like (same logic as above)

mapped.Name = Model.Model2?.Model3?.Model4?.Name ?? "N/A";

DotNetFiddle.Net Working Example.

(the ?? or null-coalescing operator is different than the ? or null conditional operator).

It can also be used out side of assignment operators with Action. Instead of

Action<TValue> myAction = null;

if (myAction != null)
{
  myAction(TValue);
}

It can be simplified to:

myAction?.Invoke(TValue);

DotNetFiddle Example:

using System;

public class Program
{
  public static void Main()
  {
    Action<string> consoleWrite = null;
    
    consoleWrite?.Invoke("Test 1");
    
    consoleWrite = (s) => Console.WriteLine(s);
    
    consoleWrite?.Invoke("Test 2");
  }
}

Result:

Test 2

Basically, I have applied ?. operator after Model as well. I am trying to know that whether it can be applied directly to the model or does it only work with the navigation properties?

The ? or null conditional operator operators on the left value, regardless of the type of value. And the compiler doesn't care what the value is on the right. It's simple compiler magic (meaning it does something you can already do, just in a simplified why).

For example

  var a = model?.Value;

is the same as saying

  var a = model == null ? null : model.Value;

In the second case the evaluation of checking for null has no associate with the value returned. The null conditional operator basically just always return null if the left value is null.

The type of member (Method, Field, Property, Constructor) .Value is irrelevant.

The reason your DotNetFiddle example doesn't work is because the compiler being use for the .Net 4.7.2 isn't compatible with the c# version that support the null conditional operator. Changing it to .Net 5, works:

https://dotnetfiddle.net/7EWoO5

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
  • 34
    To save people looking up what the ?? is.. It is the null-coalescing operator and will return Name if it is not null, otherwise it will return "N/A". – Steve Mar 05 '17 at 01:09
  • 6
    @Erik Philips I think you need to add **`|| Model.Model2.Model3.Model4.Name == null`** to have the same logic, otherwise in case `Model.Model2.Model3.Model4.Name` is `null`, `mapped.Name` will stay `null` – RazvanR Jun 08 '17 at 07:38
  • 2
    @ErikPhilips Not on the same page I guess. Please try to see what happens in both your cases if `Model.Model2.Model3.Model4.Name` is `null`. – RazvanR Jun 09 '17 at 06:07
  • 1
    The result is "N/A", again PLEASE READ THE FIRST COMMENT. [DotNetFiddle.Net Working Example](https://dotnetfiddle.net/TrsnYh). – Erik Philips Jun 09 '17 at 12:51
  • 7
    @ErikPhilips: That has nothing to to with the first comment, as this does not relate to your first example. In this you would jump into the `else`-branch and have `mapped.Name = Model.Model2.Model3.Model4.Name -> mapped.Name = null`, while you second example would substitute to `mapped.Name = "N/A"`. See the [edited DotNetFiddle](https://dotnetfiddle.net/vunRkC) – derM - not here for BOT dreams Jun 20 '17 at 14:09
  • Would this work: `mapped.Name = Model?.Model2?.Model3?.Model4?.Name ?? "N/A";`. Basically, I have applied `?.` operator after `Model` as well. I am trying to know that whether it can be applied directly to the model or does it only work with the navigation properties? Check this fiddle: https://dotnetfiddle.net/2BblBv – Junaid Oct 15 '21 at 07:05
  • 1
    @Junaid I've updated the question, let me know if something doesn't make sense. – Erik Philips Oct 15 '21 at 16:24
8

This is relatively new to C# which makes it easy for us to call the functions with respect to the null or non-null values in method chaining.

old way to achieve the same thing was:

var functionCaller = this.member;
if (functionCaller!= null)
    functionCaller.someFunction(var someParam);

and now it has been made much easier with just:

member?.someFunction(var someParam);

I strongly recommend this doc page.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Zeeshan Adil
  • 1,937
  • 5
  • 23
  • 42
  • Quick question..`var user = db.Users.Where(m=>m.id == id).FirstOrDefault(); Console.WriteLine(user?.id);` Would this work or `?.` only work with navigation properties? Kindly check this fiddle: https://dotnetfiddle.net/2BblBv – Junaid Oct 15 '21 at 07:05