What is the "?" operator?

Asked

Viewed 1,593 times

25

I am seeing the functions that C# 6.0 brought, and an example of code appeared:

C# 5.0

var vendor = new Company();
var location = default(string);
if (vendor != null)
  if (vendor.ContactPerson != null)
    if (vendor.ContactPerson.HomeAddress != null)
      location = vendor.ContactPerson.HomeAddress.LineOne;
Console.WriteLine(location);

C# 6.0

var vendor = new Company();
var location = vendor?.ContactPerson?.HomeAddress?.LineOne;
WriteLine(location);

Both have the same functionality, but in the second example everything is done using a conditional inline.

Make a inline if with two values is easy, but I don’t understand very well how it works.

2 answers

21


This is the operator conditional access or null Propagation or safe navigation. I haven’t decided which to use yet :) But I think the second is better.

As it was so frequent to check whether an object is null before doing some operation (as shown in the first example), it was a design pattern so used, it would be useful if the language had a facility for this.

Note that access to any member of the object can be "protected" with this operator. Methods can also be called. Obviously the call will only occur if the object is not null.

The result of an expression objeto ?. membro will be null, if the objeto be it null. And how expressions can be chained, the first null that he find all the other sub-expressions found below will be worth null also. He won’t even try to evaluate the rest, the end result will be null. And this is important, it’s a short-circuit operation, which means it doesn’t even try to perform the rest when there’s nothing else to do.

The two codes presented in the question nay are exactly equivalent. In this case it will even be, by coincidence, because it is a specific case rarely used where one wants as a result default one null. In this case the initialization of string location is a null in any situation. But think that if it had been initialized with "", that is, if it were a string empty, would be different.

On the first at the end of the operation if vendor is null, the content of location will not be changed, that is, it will be worth "". In the second code it will be worth null, after all the result of an operation with an object null is null.

Let’s see more about the operator

This code will cause an exception in the last row for trying to access a null object:

string texto = null;
string parte = "";
parte = texto?.Substring(0, 1);
WriteLine($"{parte.Length}");

Obviously we could have used the operator ?. before the Length and avoid the exception.

If you add this line:

int tamanho = parte.Length;

It makes an exception because you can’t get the size of a null object. Right? So let’s do this:

int tamanho = parte?.Length;

Resolves?

Neither compiles. After all now the expression possibly results in a null. A int cannot be null. Then we would have to do this:

int? tamanho = parte?.Length;

An voidable integer can contain all possible results of this expression, including the value null.

Only in this case, you’re using a different type than what you normally use just to solve a problem that didn’t exist. Then you better do it the old-fashioned way:

int tamanho = parte != null ? parte.Length : 0;

or by blending the old with the new:

int tamanho = parte?.Length ?? 0;

Note that the same operator may have different syntax in another context:

Cliente cliente = clientes?[0]; //isto também é o operador de propagação de nulo

Another example of simplification is in checking whether an object has a member:

(objeto as IExemplo)?.Exemplo();

If the objeto does not implement this interface IExemplo, the result of the operation will be null, therefore the method Exemplo() will not be called and will not cause error.

In thesis it would help programmers be more careful with code. There is a lot of code out there that does not give error of null Reference by coincidence. One day, it falls into the situation that the object is null and the application breaks without the unwary realizing. Although I don’t know if it will help much because there are many programmers who don’t know the "news" of C# 3, and some even of C# 2. And obviously you don’t know everything that already existed in C# 1. It will also happen that people think that this solves everything, that you should use everywhere, thoughtlessly. The operator accessing the member . or [] must still be the standard access operator.

Thread-safe

Its use may be more thread-safe in some cases by using a temporary variable to store the output of the expression. Example of gain:

//necessário para ser thread-safe
EventHandler<decimal> precoOnChanged = OnPrecoChanged;
if (precoOnChanged != null) {
    preco = value;
    precoOnChanged (this, value);
}

Turns into:

preco = value;
OnPrecoChanged?.Invoke(this, value) //Invoke é usado p/ resolver ambiguidade c/ delegate

Prevent the null from happening

A . NET 4 resource that people ignore is the use of contracts (it has been abandoned lately). With it it is possible not to need it and avoid countercheck null at runtime, detecting at development time:

public int ProcuraTeste(string texto) { //não compila se texto for null
    Contract.Requires(texto != null); //isto pode ser eliminado do runtime
    return texto.IndexOf("teste");
}

I put in the Github for future reference.

Of course this is not the solution for everything. There are cases that you can only know at runtime, that is, null is something expected as a valid value. There’s a lot of confusion about what a zero is. If it was invalid, the type system, compiler or static analysis should detect and prevent this.

Simplifying without this operator

As additional information, in C# 5 you can simplify the code a little:

if (vendor != null && vendor.ContactPerson != null && vendor.ContactPerson.HomeAddress != null)
    location = vendor.ContactPerson.HomeAddress.LineOne;
  • Interesting question of contracts. Just a question, how long has it been that program in C#/. NET

  • Complicated answer. 14 years? or 0 years?

  • 1

    I think this question of the term is important, sometimes languages have a different term for exactly the same behavior, but because of the context of the language the term changes. In Ruby it is called Safe Navigation, as there is no null there (only nil), it does not make sense the term Null Propagation, whereas in C# it makes much more sense, it is more explicit that the type of return will be a Nullable.

9

This code is not about inline ifs, but regarding assessments of NULL cascading.

In the above example, the developer wants to get the value of vendor.ContactPerson.HomeAddress.LineOne.

However, several properties need to be tested by values null: vendor, ContactPerson, HomeAddress and - finally - LineOne.

In C#5 or lower, it would be necessary to implement a test for each object.

With the new syntax, you can now evaluate NULL string in a single line.

  • So that means that this is only for cases where I want to assess whether a value is or is not equal to null

  • @Ezequielbarbosa Exactly. And many implementations need this - for example, HttpContext.Current.Request for web applications. There may be no current context, or a Request.

  • 1

    FWIW, This operator is called "Null conditional Operator".

Browser other questions tagged

You are not signed in. Login or sign up in order to post.