使用三元语法将参数设置为 DBNull.Value 会出错?
Posted
技术标签:
【中文标题】使用三元语法将参数设置为 DBNull.Value 会出错?【英文标题】:Setting parameter to DBNull.Value using ternary syntax gives error? 【发布时间】:2012-06-06 20:48:02 【问题描述】:我有以下代码来设置一个参数,该参数将在 INSERT 语句中用于设置 SQL Server 数据库中的 VARCHAR 列。我的值对象(名为 ilo)有一个名为 Description 的属性,该属性被初始化为 String.Empty,然后设置为从 XML 读取的某个值,或者如果该 XML 元素为空,它就保持为 String.Empty。
所以在插入数据库时,如果属性仍然设置为String.Empty,我想让它插入一个空值。
database.AddInParameter(cmd, "@description", DbType.String,
(ilo.Description.Equals(string.Empty)) ?
DBNull.Value :
ilo.Description);
所以基本上我是说,如果 ilo.Description 等于 string.empty,则将参数设置为 DBNull.Value,否则将其设置为 ilo.Description。
这会在 Visual Studio 中出现以下错误...
错误 141 无法确定条件表达式的类型,因为 'System.DBNull' 和 'string' 之间没有隐式转换
为什么?
奇怪的是,我可以毫无错误地执行以下操作,这应该与使用上面的内联条件语法完全相同!?!
if(ilo.Description.Equals(string.Empty))
database.AddInParameter(cmd, "@description", DbType.String, DBNull.Value);
else
database.AddInParameter(cmd, "@description", DbType.String, ilo.Description);
我搜索了其他帖子,找到了下面的帖子,但它并没有真正回答我的问题。
EntLib Way to Bind "Null" Value to Parameter
我对 WHY 更感兴趣,因为显而易见的解决方法是只使用 if/else 语句而不是内联(三元)语法?
在这个链接上有一个答案,但我想要一个更好的解释,因为这对我来说似乎是 BS,这不起作用;我会称之为错误!
http://msdn.microsoft.com/en-us/library/ty67wk28.aspx
编辑:2021 年 3 月 30 日,我写这个问题已经 9 年了。最后,从 C# 9 开始,此问题已得到修复。三元表达式现在支持混合类型,只要它们可以被隐式转换。
【问题讨论】:
您可以获取有关三元运算符和此类问题的详细信息in this answer 谢谢史蒂夫。你的链接是我真正想要的。我认为这是 .NET 的一个愚蠢方面。他们为什么不只评估每个可能结果的类型是否符合陈述。即如果你说 Object o = (someBool) ? someInt32 : someString;你得到一个错误,但是评估两个结果是否可以隐式转换为一个对象,而不是评估是否可以将 someString 转换为 someInt32 有多容易?这对我来说似乎很愚蠢,但我想就是这样。谢谢! 我还想评论一下,我对该主题的回复速度和准确性印象深刻。这个社区太棒了!谢谢大家! 【参考方案1】:这是人们在使用条件运算符时经常遇到的错误。要修复它,只需将一个或两个结果转换为一个通用的基本类型。
ilo.Description.Equals(string.Empty)
? (object)DBNull.Value
: ilo.Description
您看到的错误消息中揭示了该问题。
无法确定条件表达式的类型,因为'System.DBNull'和'string'之间没有隐式转换
字符串不是 DBNull,DBNull 也不是字符串。因此,编译器无法确定表达式的类型。通过使用转换为通用基本类型(在本例中为object
),您创建了一个场景,编译器随后可以确定字符串也可转换为对象,因此表达式的类型可以确定为对象,即也非常适合您的代码行也期望作为 DbParameter 参数。
【讨论】:
史蒂夫的评论提供了一个包含更多细节的链接,但您的回答也非常正确。对我来说必须这样做似乎很愚蠢。我相信 Java 不会发生这种情况。【参考方案2】:这是我在另一个帖子中发现的,对我来说效果很好:
yourVariable ?? (object)DBNull.Value
希望对你有帮助。
【讨论】:
这是错误的 - ??测试yourVariable
是否为 null,而不是字符串是否为空,正如 OP 所要求的那样。【参考方案3】:
安东尼确实是正确的,所以他应该得到正确的答案,但是这里有一个扩展方法,因为我很无聊......
public static object NullCheck(this string self)
return (string.IsNullOrEmpty(self)) ? (object)DBNull.Value : self;
在您的场景中的用法:
database.AddInParameter(cmd, "@description", DbType.String,
ilo.Description.NullCheck());
【讨论】:
好东西。尽管我可能不会使用这种方法,但它只是教会了我一些我以前不知道的关于 C# 的东西;就像我之前甚至没有注意到 String 上的 IsNullOrEmpty 方法一样。我只是非常习惯 Java,很高兴学习更多 C#。谢谢! 不用担心,经过考虑,最好将扩展方法放在 ParameterCollection / 数据库对象本身上,以提供一个包装器,以您想要的方式处理空值。【参考方案4】:您会收到编译错误,因为三元表达式的两个部分必须属于同一类型。对于这种特殊情况,最简单的解决方法是将两者都转换为一个对象:
database.AddInParameter(cmd, "@description", DbType.String,
(ilo.Description.Equals(string.Empty)) ?
(object) DBNull.Value :
(object) ilo.Description);
【讨论】:
正如lazyberezovsky 建议的那样,这里最好使用null 而不是DBNull.Value。我认为您只需要在从数据读取器或数据集读取时使用 DBNull.Value。以上是关于使用三元语法将参数设置为 DBNull.Value 会出错?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Nullable DateTime 变量的 null 值转换为 DbNull.Value
OracleParameter 和 DBNull.Value
为啥我不能将 DBNull.Value 插入到 sql server 2005 中的可为空的图像字段中?
我应该用啥来比较 DBNull ?使用 DBNull.Value 或 ToString().IsNullOrEmpty()