Home > Mobile >  Call extension methods for Nullable<T> with ?. in chain
Call extension methods for Nullable<T> with ?. in chain

Time:11-10

Why does C# not allow to concat methods with ?. in chain?

class X {
  public static Timestamp ToTimestamp(this System.DateTime dateTime);

  public void Demo()
  {
    System.DateTime? dateTime = GetFromSomewhere();
    Timestamp? good = (dateTime?.ToUniversalTime())?.ToTimestamp();
    Timestamp? bad = dateTime?.ToUniversalTime()?.ToTimestamp();
  }
}

I was very surprised that the line with bad gives a compilation error:

error CS0023: Operator '?' cannot be applied to operand of type 'DateTime'

How adding of braces can change the type here?

CodePudding user response:

This code:

Timestamp? good = (dateTime?.ToUniversalTime())?.ToTimestamp();

is equivalent to this:

DateTime? temp = dateTime?.ToUniversalTime();
Timestamp? good = temp?.ToTimestamp();

The original code evaluates the expression in the parentheses first, which can be a DateTime or can be null. That means that using a null-forgiving operator is allowed. This code:

Timestamp? bad = dateTime?.ToUniversalTime()?.ToTimestamp();

is not the same. In order for ToUniversalTime to be called, dateTime must not be null, so the result of calling ToUniversalTime cannot be null, so you can't apply a null-forging operator to that result. That code is equivalent to this:

Timestamp? bad = dateTime == null
                     ? null
                     : dateTime.Value.ToUniversalTime()?.ToTimestamp();

The result of dateTime.Value.ToUniversalTime() is not nullable so the null-forgiving operator is not valid.

CodePudding user response:

Your syntax is wrong:

Timestamp? bad = dateTime?.ToUniversalTime()?.ToTimestamp();

ToUniversalTime() returns DateTime, non-nullable. You can simply use: dateTime?.ToUniversalTime().ToTimestamp()

if datetime is null, null will be returned, else ToUniversalTime().ToTimestamp() will be called.

That is why (dateTime?.ToUniversalTime())?.ToTimestamp() does work, if dateTime?.ToUniversalTime() is null, the value will be null, else .ToTimestamp() will be called.

Notice the difference here;

dateTime?.ToUniversalTime().ToTimestamp() Will return null, or whatever ToTimeStamp() returns.

(dateTime?.ToUniversalTime())?.ToTimestamp() will always return whatever ToTimeStamp() returns

CodePudding user response:

You cannot use the null conditional operator on non-nullable(primitive) types like DateTime.

Why this works?

Timestamp? good = (dateTime?.ToUniversalTime())?.ToTimestamp();

Because the expression in brackets returns a Nullable<DateTime>, so can be null (dateTime is a Nullable<DateTime> which is the same as DateTime?).

Why this does not work?

Timestamp? bad = dateTime?.ToUniversalTime()?.ToTimestamp();

Because ToUniversalTime returns a DateTime and not a DateTime?, so can never be null.

So this works:

Timestamp? good2 = dateTime?.ToUniversalTime().ToTimestamp();
  • Related