Convert decimal? to decimal in earlier versions of .NET (C# Version 7.3)

Viewed 438

So after searching for similar questions, I haven't seen any results.

The error that keeps popping up is

Feature 'target-typed conditional expression' is not available in C# 7.3. Please use language version 9.0 or greater.

The code:

.Select(x => new FinancialStatementDto
 {
   Uid = Guid.NewGuid(),
   AccountNumber = x.Key.AccountNumber,
   Credit = x.Any(y => y.Credit.HasValue) ? Math.Abs((decimal)x.Sum(y => y.Credit)) : null,
   Debit = x.Any(y => y.Debit.HasValue) ? x.Sum(y => y.Debit) : null,
   AccountName = x.Key.AccountName
 });

The error pops up on Credit = x.Any(y => y.Credit.HasValue) ? Math.Abs((decimal)x.Sum(y => y.Credit)) : null,

Credit is defined as decimal? however the Math.Abs function doesn't allow nullable values.

Any ideas?

P.S. It must be done on version 7.3

3 Answers

The problem is that the left side of your conditional is a non-nullable decimal, while the right side is null. There is no conversion between the two, and the language prior to C# 9 does not care about the target of the assignment being the common type (i.e. decimal?).

Adding a cast to decimal? on the left side will fix the issue:

Credit = x.Any(y => y.Credit.HasValue)
    ? (decimal?)Math.Abs((decimal)x.Sum(y => y.Credit))
    : null,

You get this error because you have an expression of the kind someBool ? someDecimal : null, and C# prior to 9 cannot yet use the the assignment target to infer the return type decimal?.

The usual workaround is to explicitly type either expression with the nullable target type, i.e.:

 someBool ? someDecimal : (decimal?)null

or

 someBool ? someDecimal : new decimal?()

or

 someBool ? (decimal?)someDecimal : null

Note that this workaround is still required even in C# 9 if the compiler does not know the target type:

decimal? d = someBool ? someDecimal : null;       // compiles in C# 9 and above
var d = someBool ? someDecimal : null;            // never compiles
var d = someBool ? someDecimal : (decimal?)null;  // always compiles

(Nitpick: And by "always" I mean "C# 2.0 and above", since nullable types were introduced in C# 2.0.)

Use this

Credit = x.Any(y => y.Credit.HasValue) ? Math.Abs(x.Sum(y => y.Credit ?? 0)) : null
Related