SqlParameter 的奇怪行为

Strange behavour with SqlParameter

使用 .Net 4.5.2 我有以下示例代码...

var cmd = new SqlCommand();
cmd.Parameters.Add(new SqlParameter("@CONTENTHYPERLINK", SqlDbType.VarChar, 50));
cmd.Parameters["@contentHyperlink"].Value = "hello world";

第三个 link 导致 IndexOutOfRangeException 异常

但是如果我使用下面的任何(这纯粹改变了参数名称的大小写)它就有效!

cmd.Parameters["@CONTENTHYPERLINK"].Value = "hello world";
cmd.Parameters["@contenthyperlink"].Value = "hello world";
cmd.Parameters["@contenTHYperlink"].Value = "hello world";

如果我使用以下任何,它不会工作...

cmd.Parameters["@contentHyperlink"].Value = "hello world";
cmd.Parameters["@contentHYPERLINK"].Value = "hello world";
cmd.Parameters["@CONTENtHYPERLINK"].Value = "hello world";

(还有很多行之有效和行不通的例子,我这​​里就不一一列举了。)

到底为什么不区分大小写的东西在特定情况下会抛出异常?

(我意识到问题的解决方案是使用不会导致异常的方法,但我想知道为什么会这样)


更新

将代码更改为使用大写字母后,另一个存储过程参数发生了完全相同的事情...

cmd.Parameters["@PortalLastLogon"]  <-- Fails
cmd.Parameters["@portalLastlogon"]  <-- Fails

cmd.Parameters["@PORTALLASTLOGON"]  <-- Works
cmd.Parameters["@portallastlogon"]  <-- Works

这快把我逼疯了...如果我还有头发可以拔掉,我会像现在一样秃头。

任何人 都可以解释一下到底发生了什么吗?!

我有一个软件有超过 2400 个 sproc 参数...我没有时间更新它们!

我发现发生这种情况的原因是我们最近引入了语言文化处理代码。

在我的 ASP.Net 网络应用程序的 [Global].Application_BeginRequest 部分中,我正在设置以下...

var culture = new Globalization.CultureInfo(cultureCode);
Threading.Thread.CurrentThread.CurrentCulture = culture;
Threading.Thread.CurrentThread.CurrentUICulture = culture;

我正在使用的特定语言是威尔士语(代码 cy)...在对这种文化的不区分大小写的检查中一定有一些非常奇怪的东西,这意味着它不匹配。

我把它改回英文的那一刻,问题就消失了。

此时我没有关于如何的答案我将在不将每个存储过程调用更新为大写的情况下解决这个问题...但是至少我有理由 为什么 它失败了。


深入研究 the .Net source code shows that the IndexOf is using both EntityUtil.SrcCompare which does a straight == comparison... but also EntityUtil.DstCompare,它基于 Compare 的文化。

所以至少我有证据表明文化正在产生影响。


下面将演示该问题(使用与 EntityUtil.DstCompare 相同的 CompareOptions)...

using System.Threading;
using System.Globalization;

Thread.CurrentThread.CurrentCulture = new CultureInfo("en");
var enResult = CultureInfo.CurrentCulture.CompareInfo.Compare("lL", "LL",
    CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase);
// enResult == 0 as expected

Thread.CurrentThread.CurrentCulture = new CultureInfo("cy");
var cyResult = System.CurrentCulture.CompareInfo.Compare("lL", "LL",
    CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase);
// cyResult == -1 

由于我需要系统在运行文化下,我只好写了一个脚本来更新所有Parameters[xxx]以完全匹配定义的大小写。