可空值类型的条件运算符赋值?

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

我经常发现自己想做这样的事情(EmployeeNumber是一个Nullable<int>,因为它是一个LINQ-to-SQL dbml对象上的属性,其中列允许NULL值)。不幸的是,编译器认为

在 'null' 和 'int' 之间没有隐式转换

即使这两种类型单独赋值给可空int都是有效的。

使用空合并运算符似乎不是一个选项,因为如果.Text字符串不为空,则需要进行内联转换。

据我所知,唯一的方法是使用if语句和/或分两步赋值。在这种特定情况下,我觉得这非常令人沮丧,因为我想使用对象初始化器语法,并且此赋值将在初始化块中...

有人知道更优雅的解决方案吗?


1
请查看Eric Lippert的相关博客文章:类型推断问题,第一部分 - CodesInChaos
1
编译器错误 CS0173 将我带到了这里。 - DavidRR
C#9支持条件表达式的目标类型推断,这可以减少出现此问题的机会。在本问题中给出的示例中,如果EmployeeNumber属性的类型为int?,编译器将从中推断出类型,但如果分配给更一般化的类型(如object)或新声明的var变量,则仍会出现错误。 - binki
6个回答

77
问题出在条件运算符没有考虑值如何使用(在这种情况下赋值)来确定表达式的类型,而只考虑真/假的值。在这种情况下,你有一个null和一个Int32,而类型不能被确定(有实际原因不能仅仅假设Nullable<Int32>)。如果你真的想以此方式使用它,你必须自己将其中一个值转换为Nullable<Int32>,这样C#可以解析类型:
EmployeeNumber =
    string.IsNullOrEmpty(employeeNumberTextBox.Text)
    ? (int?)null
    : Convert.ToInt32(employeeNumberTextBox.Text),
或者
EmployeeNumber =
    string.IsNullOrEmpty(employeeNumberTextBox.Text)
    ? null
    : (int?)Convert.ToInt32(employeeNumberTextBox.Text),

6
你也可以写成 new int?() - SLaks
7
您说它不能承担 Nullable<Int32>,有什么实际原因呢? - BlueMonkMN
2
@SLaks 或者 default(int?) - IS4
真正的原因是什么?我也看不出来真正的原因。 - user1060500

8
我认为可以使用一个实用方法来使代码更加简洁易懂。
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);
    }
}

那么

EmployeeNumber = Convert.To<int>(employeeNumberTextBox.Text, Int32.Parse);

这是一个非常好的想法,也是泛型和扩展方法极其强大的例子 :) - Grank

6

虽然Alex提供了正确和接近问题的答案,但我更喜欢使用TryParse

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

使用 TryParse 更加安全,它可以处理无效输入以及空字符串的情况。否则,如果用户输入类似于 1b 的内容,将会出现未处理异常并显示错误页面,这是由于 Convert.ToInt32(string) 导致的。


我更喜欢使用ASP.NET CompareValidator验证用户的输入,可以将其设置为DataTypeCheck运算符和int类型。这可以确保输入永远不会是除整数以外的任何内容,并且如果可能的话,可以在客户端执行。 - Grank

3
您可以将Convert的输出转换为:
EmployeeNumber = string.IsNullOrEmpty(employeeNumberTextBox.Text)
   ? null
   : (int?)Convert.ToInt32(employeeNumberTextBox.Text)

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;

编辑: 以上简要解释,我试图在变量X1中获取Posid的值(如果它是非空的int且具有大于0的值)。 我不得不在Posid.Value上使用(int?),以使条件运算符不抛出任何编译错误。 只是一个FYI,GetHolidayCount是一个可能返回null或任何数字的WCF方法。 希望这可以帮助。


通常建议您在发布代码时附上代码描述,而不仅仅是贴出代码。这有助于提问者(以及遇到相同问题的其他人)了解您的解决方案正在做什么。 - Robert Rouhani

0

C# 9.0 开始,这将终于成为可能:

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

这意味着问题中的代码块也将编译而不会出错。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接