【发布时间】:2013-01-08 21:37:44
【问题描述】:
首先,一些背景知识。阅读问题和接受的答案posted here,了解我的问题的具体情况。我不确定是否存在其他类似的案例,但这是我知道的唯一案例。
上面的“怪癖”是我很早就意识到的。直到最近我才完全了解原因。
Microsoft 关于SqlParameter 类的文档对这种情况提供了更多说明。
当您在 value 参数中指定
Object时,SqlDbType是 从 Object 的 Microsoft .NET Framework 类型推断。使用
SqlParameter构造函数的重载时要小心 指定整数参数值。因为这个重载需要一个Object类型的值,您必须将整数值转换为Object键入值为零时,如以下 C# 示例所示。
Parameter = new SqlParameter("@pname", Convert.ToInt32(0));如果你这样做 不执行此转换,编译器假定您正在尝试 调用SqlParameter(string, SqlDbType) 构造函数重载。
(强调。添加)
我的问题是,为什么编译器会假定当您指定硬编码“0”(并且只有值“0”)时,您正在尝试指定枚举类型,而不是整数类型?在这种情况下,它假定您声明的是 SqlDbType 值,而不是值 0。
这是不直观的,更糟糕的是,错误是不一致的。我有我编写的旧应用程序多年来一直调用存储过程。我将对应用程序进行更改(通常甚至与我的 SQL Server 类无关),发布更新,这个问题会突然破坏应用程序。
当一个包含多个方法签名的对象包含两个相似的签名,其中一个参数是对象/整数而另一个接受枚举时,为什么编译器会被值 0 混淆?
正如我所提到的,我从未将这视为任何其他构造函数或任何其他类的方法的问题。这是 SqlParameter 类独有的还是 C#/.Net 中继承的错误?
【问题讨论】:
-
与您的问题没有直接关系,但我认为更好的建议是使用命名参数 (
new SqlParameter("@pname", value: 0)) 而不是Convert.ToInt32()。 -
为什么人们不总是指定 dbtype 和 length?不这样做会导致难以检测到问题并破坏计划缓存。只是为了节省一些击键还是有其他好处?
-
@adrianm,这是因为存在接受参数名称和值的构造函数。如果不能使用,为什么要在 SqlParameter 类上有构造函数?这不是关于保存击键,而是关于在类上使用构造函数,因为它们是两个构造函数之间的伪冲突,因为一个接受一个对象,另一个接受一个枚举。如果这是“糟糕的编码习惯”,那么首先不应该存在接受值的构造函数。
-
与其在
new SqlParameter("@pname", Convert.ToInt32(0))中进行不必要的方法调用,不如通过直接使用强制转换语法指定所需类型来解决问题,如new SqlParameter("@pname", (object)0)中所示。当重载决议选择错误的重载(或拒绝选择任何重载)时,这是通常要做的事情。一般来说,如果像M(a, b, c, d)这样的东西不起作用,请在需要的地方插入精确的类型,例如M((T1)a, b, (T2)c, d)。
标签: c# .net compiler-construction