为啥SqlParameter名称/值构造函数将0视为null?

Posted

技术标签:

【中文标题】为啥SqlParameter名称/值构造函数将0视为null?【英文标题】:Why does the SqlParameter name/value constructor treat 0 as null?为什么SqlParameter名称/值构造函数将0视为null? 【发布时间】:2012-01-11 05:48:54 【问题描述】:

我在一段代码中观察到一个奇怪的问题,即即席 SQL 查询没有产生预期的输出,即使它的参数与数据源中的记录匹配。我决定在即时窗口中输入以下测试表达式:

new SqlParameter("Test", 0).Value

这给出了null 的结果,这让我摸不着头脑。 SqlParameter 构造函数似乎将零视为空值。以下代码产生正确的结果:

SqlParameter testParam = new SqlParameter();
testParam.ParameterName = "Test";
testParam.Value = 0;
// subsequent inspection shows that the Value property is still 0

谁能解释这种行为?是不是故意的?如果是这样,那可能是相当危险的......

【问题讨论】:

关于这个主题的进一步阅读:***.com/questions/14224465/… 【参考方案1】:

正如documentation 中针对该构造函数所述:

当您在 value 参数中指定 Object 时,SqlDbType 是从 Object 的 Microsoft .NET Framework 类型推断出来的。

使用SqlParameter 构造函数的此重载来指定整数参数值时要小心。由于此重载采用 Object 类型的值,因此当值为零时,您必须将整数值转换为 Object 类型,如以下 C# 示例所示。

Parameter = new SqlParameter("@pname", (object)0);

如果您不执行此转换,编译器会假定您正在尝试调用 SqlParameter (string, SqlDbType) 构造函数重载。

您只是调用了与您的情况不同的构造函数。

原因是 C# 允许从整数文字 0 到枚举类型(它们只是下面的整数类型)的 隐式 转换,而这种隐式转换会导致 (string, SqlDbType) 构造函数比将int 转换为object(string, object) 构造函数所需的装箱转换更适合重载解析。

当您传递int 变量 时,这绝不会成为问题,即使该变量的值是0(因为它不是零字面量)或任何其他表达式类型为int。如果您如上所示将int 显式转换为object,也不会发生这种情况,因为只有一个匹配的重载。

【讨论】:

我遇到了这个问题并尝试了一个不起作用的不同解决方案:为什么我尝试的 Parameter = new SqlParameter("@pname", (int)0); 不起作用时建议的 Parameter = new SqlParameter("@pname", Convert.ToInt32(0)); 起作用? @mortb,您必须为此查阅语言规范,但我的猜测是,重载解析在第一种情况下会关心确切的类型,但在第二种情况下可能允许枚举,因为您' 仍在传递int 类型的文字。 我找到了原因:***.com/questions/3153841/… 文字 0 将始终被评估为匹配枚举的类型,而其他数字则不会。似乎有点晦涩... 引用的示例有问题:Convert.ToInt32(0) 不会更改选择的重载。代码应该是new SqlParameter("@pname", (object)0); @Steven:如果我错了,请纠正我,但只有 literal 0 可以隐式转换为任何枚举类型。因此,返回int 的方法调用很好,可以选择另一个重载。不可否认,自从我查看规范以来已经有几个月了,但是 afaik 它就是这样工作的。【参考方案2】:

在传递/添加参数时使用类型化数据是一种很好的做法。

您可以通过以下方式完成以下任务:

对于字符串/varchar 类型的数据:

SqlParameter pVarchar = new SqlParameter
                    
                        ParameterName = "Test",
                        SqlDbType = System.Data.SqlDbType.VarChar,
                        Value = string.Empty,
                    ;

对于 int 类型的数据:

SqlParameter pInt = new SqlParameter
                    
                        ParameterName = "Test",
                        SqlDbType = System.Data.SqlDbType.Int,
                        Value = 0,
                    ;

您可以根据您使用的数据更改SqlDbType的值。

【讨论】:

虽然通常很有帮助,但从技术上讲,这并不是问题的答案。因此它应该是一个评论。

以上是关于为啥SqlParameter名称/值构造函数将0视为null?的主要内容,如果未能解决你的问题,请参考以下文章

为啥可以通过构造函数将临时值分配给引用?

为啥我不能将类构造函数参数设置为默认值?

为啥在按值返回时总是调用复制构造函数

C#中,求一个返回类型为DataTable,并用SqlParameter传参的SqlHelper

为啥在通过 const 引用传递临时值时调用复制构造函数?

当我们将对象作为参数传递给方法时,为啥会调用复制构造函数?