Conditional operator assignment with Nullable<value> types?
Asked Answered
D

6

66
EmployeeNumber =
string.IsNullOrEmpty(employeeNumberTextBox.Text)
    ? null
    : Convert.ToInt32(employeeNumberTextBox.Text),

I often find myself wanting to do things like this (EmployeeNumber is a Nullable<int> as it's a property on a LINQ-to-SQL dbml object where the column allows NULL values). Unfortunately, the compiler feels that

There is no implicit conversion between 'null' and 'int'

even though both types would be valid in an assignment operation to a nullable int on their own.

Using the null coalescing operator is not an option as far as I can see because of the inline conversion that needs to happen on the .Text string if it's not null.

As far as I know the only way to do this is to use an if statement and/or assign it in two steps. In this particular case I find that very frustrating because I wanted to use the object initializer syntax and this assignment would be in the initialization block...

Does anyone know a more elegant solution?

Dibranchiate answered 16/9, 2008 at 19:1 Comment(3)
Check Eric Lippert's related blog entry: Type inference woes, part oneDiabolo
Compiler Error CS0173 brought me here.Faceharden
C#9 supports target typing of conditional expressions which reduces the chance you will hit this issue. In the example given in this question, the compiler would infer the type from the EmployeeNumber property if its type is int?, but you would still get the error if assigning to a more generalized type like object or to a newly declared var variable.Uranography
A
77

The problem occurs because the conditional operator doesn't look at how the value is used (assigned in this case) to determine the type of the expression -- just the true/false values. In this case, you have a null and an Int32, and the type can not be determined (there are real reasons it can't just assume Nullable<Int32>).

If you really want to use it in this way, you must cast one of the values to Nullable<Int32> yourself, so C# can resolve the type:

EmployeeNumber =
    string.IsNullOrEmpty(employeeNumberTextBox.Text)
    ? (int?)null
    : Convert.ToInt32(employeeNumberTextBox.Text),

or

EmployeeNumber =
    string.IsNullOrEmpty(employeeNumberTextBox.Text)
    ? null
    : (int?)Convert.ToInt32(employeeNumberTextBox.Text),
Albite answered 16/9, 2008 at 19:8 Comment(4)
You can also write new int?().Hypocrite
You say there are real reasons it can't assume Nullable<Int32>. What reasons?Caundra
@Hypocrite Or default(int?).Adventitia
Real reasons? I can't see real reasons either.Justinejustinian
H
8

I think a utility method could help make this cleaner.

public static class Convert
{
    public static T? To<T>(string value, Converter<string, T> converter) where T: struct
    {
        return string.IsNullOrEmpty(value) ? null : (T?)converter(value);
    }
}

then

EmployeeNumber = Convert.To<int>(employeeNumberTextBox.Text, Int32.Parse);
Hereafter answered 16/9, 2008 at 19:20 Comment(1)
That's a really good idea, and an example of where generic and extension methods are extremely awesome :)Dibranchiate
D
6

While Alex provides the correct and proximal answer to your question, I prefer to use TryParse:

int value;
int? EmployeeNumber = int.TryParse(employeeNumberTextBox.Text, out value)
    ? (int?)value
    : null;

It's safer and takes care of cases of invalid input as well as your empty string scenario. Otherwise if the user inputs something like 1b they will be presented with an error page with the unhandled exception caused in Convert.ToInt32(string).

Durning answered 16/9, 2008 at 19:32 Comment(1)
I prefer to validate the user's input using the ASP.NET CompareValidator, which can be set to an Operator of DataTypeCheck and a Type of int. This ensures that the input will never be anything other than an integer, and does it client-side if it can.Dibranchiate
P
3

You can cast the output of Convert:

EmployeeNumber = string.IsNullOrEmpty(employeeNumberTextBox.Text)
   ? null
   : (int?)Convert.ToInt32(employeeNumberTextBox.Text)
Phylloquinone answered 16/9, 2008 at 19:5 Comment(0)
P
1
//Some operation to populate Posid.I am not interested in zero or null
int? Posid = SvcClient.GetHolidayCount(xDateFrom.Value.Date,xDateTo.Value.Date).Response;
var x1 = (Posid.HasValue && Posid.Value > 0) ? (int?)Posid.Value : null;

EDIT: Brief explanation of above, I was trying to get the value of Posid (if its nonnull int and having value greater than 0) in varibale X1. I had to use (int?) on Posid.Value to get the conditional operator not throwing any compilation error. Just a FYI GetHolidayCount is a WCF method that could give null or any number. Hope that helps

Pretor answered 24/4, 2015 at 15:31 Comment(1)
It's generally recommended that you include a description of what your code does instead of just posting the code. This helps the person asking the question (and people who have found this question while experiencing the same issue) understand what your solution is doing.Durance
V
0

As of C# 9.0, this will finally be possible:

Target typed ?? and ?:

Sometimes conditional ?? and ?: expressions don’t have an obvious shared type between the branches. Such cases fail today, but C# 9.0 will allow them if there’s a target type that both branches convert to:

Person person = student ?? customer; // Shared base type
int? result = b ? 0 : null; // nullable value type

That means the code block in the question will also compile without errors.

EmployeeNumber =
string.IsNullOrEmpty(employeeNumberTextBox.Text)
    ? null
    : Convert.ToInt32(employeeNumberTextBox.Text),
Varian answered 4/7, 2020 at 10:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.