Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 可能的非预期参考比较按预期进行_C#_Asp.net_.net 4.5 - Fatal编程技术网

C# 可能的非预期参考比较按预期进行

C# 可能的非预期参考比较按预期进行,c#,asp.net,.net-4.5,C#,Asp.net,.net 4.5,我有类似以下代码: this.Session[key] = "foo"; if ((this.Session[key] ?? string.Empty) == "foo") { //do stuff } 当然,这会造成“可能的非预期参考比较按预期进行”的情况。这方面的解决方案在这里有很好的文档记录,我已经知道修复方法是在看到代码后立即将会话变量转换为字符串 但是,该代码已有多年历史,自最初编写以来从未更改过。直到本周,在我们的测试环境中,if语句的计算结果为true,并执行了//do

我有类似以下代码:

this.Session[key] = "foo";

if ((this.Session[key] ?? string.Empty) == "foo")
{
    //do stuff
}
当然,这会造成“可能的非预期参考比较按预期进行”的情况。这方面的解决方案在这里有很好的文档记录,我已经知道修复方法是在看到代码后立即将会话变量转换为
字符串

但是,该代码已有多年历史,自最初编写以来从未更改过。直到本周,在我们的测试环境中,
if
语句的计算结果为true,并执行了
//do stuff
部分。此错误代码仍在我们的生产环境中按预期工作


这怎么可能?没有理由认为编写的代码应该按预期工作;但它确实做到了,而且在生产中仍然如此。那么,是什么改变了这段本不应该工作但却突然停止工作的代码(或者更确切地说,它的行为应该一直如此)?

您很幸运,比较成功了!在您的示例中,字符串“foo”是,即两个字符串文本存储一次,并且具有相同的引用。但是,如果两个foo中的一个在另一个程序集中定义,或者反序列化,或者以某种方式在代码中构造(例如
string s=“f”;string t=s+“oo”
),则引用可能不同。由于
会话[key]
被键入为对象,因此将执行引用比较

不需要合并,但是铸件是:

if ((string)Session[key] == "foo") { ... } // This will perform a textual comparison.
您也可以这样写(因为
Equals
是多态的):

仅比较两个字符串值是不够的,它们必须静态键入为
string
,才能作为字符串进行比较

Jon Skeet关于这个主题的相关、非常有趣的帖子:

字符串文字“foo”是。这意味着每次使用它时,都会引用相同的对象

公共语言运行库通过维护一个名为intern pool的表来保存字符串存储,该表包含对程序中以编程方式声明或创建的每个唯一文本字符串的单个引用。因此,具有特定值的文本字符串的实例在系统中只存在一次

例如,如果将相同的文本字符串分配给多个变量,则运行时将从intern池检索对文本字符串的相同引用,并将其分配给每个变量

这就是为什么
object.ReferenceEquals(“foo”,“foo”)
是真的

如果对动态创建的字符串执行相同的操作,则该字符串将不会被插入,引用也将不相等

object str = new StringBuilder().Append("f").Append("oo").ToString(); // str = "foo"
object.ReferenceEquals(str, "foo");                                   // false

根据实现的不同,字符串实习可能会有不同的工作方式,这就是为什么在通过引用比较字符串时,可以在不同的环境中获得不同的行为。

在测试环境中会话是否处于进程外?在这个问题中,我被两件事弄糊涂了。首先,这个问题包含一个逻辑谬误:代码的行为总是一样的。它比较了两个参考文献的平等性。如果它产生true,那是因为引用是相等的。如果它一致地生成true,则引用一致地相等。我不明白你在这里对什么感到困惑。其次,在我的一生中,我无法理解空合并操作符在这里的含义。代码的意思是“如果值为null,则将空与null进行比较”,但为什么?如果为空,则该值已不是“foo”!
会话[键]
设置的准确程度如何?它与什么相比?您在测试和生产环境中使用哪个版本的.NET framework?这两种环境之间一定存在某种差异,导致字符串实习的工作方式不同。您发布的代码使用了2个字符串文字-除非在程序集级别关闭了“interning”,否则这些文字将始终处于“interning”。@EricLippert-我从实际实现中过度简化了我的示例。在实际代码中,会话变量是在另一个模块中根据可能存在或不存在的查询字符串参数设置的。存在null合并是因为如果会话变量最终为null,它将引发异常。此外,我的困惑在于,用于一致计算true的代码。现在它一直在计算false。如果会话变量为null,null合并将无助于防止异常,它只转换从会话变量检索到的null值。但要实现这一点,会话变量必须为非null,否则索引将失败。null coalesce操作符在比较中没有帮助,因为
string.Empty==“foo”
null==“fool”
都返回
false
(如果将字符串与
null
进行比较,则不会引发异常)。如果您还包括了一个如何“正确”执行该操作的示例(
Object.Equals)(.this.Session[key]?string.Empty),“foo”)
,使用Object.Equals检查Equals函数的重载,以便在两个对象都不是其真实类型且为空时工作。)@ScottChamberlain这是一种非常迂回的代码更正方法。最直接的方法是将会话[key]
转换为字符串,并使用适当的字符串比较。@phoog
Session[key]
可以保存字符串,也可以不保存字符串。我同意它是最正常的程序,它将始终是相同的类型,但它已经被证明,遗留代码已经出错,因此我不知道它是否可以被信任,它将永远不会在会话变量中存储除字符串以外的任何内容。@ScottChamberlain很公平。但是,如果我必须编码返回值可能不是字符串的可能性,我可能会显式地处理它,而不是相信没有人会在将来的某个时候将对象转换为
=
。@ScottChamberlain OP知道如何修复代码以使用
=
的字符串重载。我想把它放进去
object str = new StringBuilder().Append("f").Append("oo").ToString(); // str = "foo"
object.ReferenceEquals(str, "foo");                                   // false