引用相等性能差异?((object)obj1==(object)obj2)与object.ReferenceEquals(obj1,obj2)使用object.ReferenceEquals方法((object)obj1==(object)obj2)是否有任何额外开销?在第一种情况下,将涉及静态方法调用,而在这两种情况下,都将涉及对象的某种形式的转换。即使编译器平衡了这些方法,不平等又如何呢?(object)obj!=nullcomparedto...!object.ReferenceEquals(obj,null)我想在某个时候,会有!逻辑否定发生在=运算符内,或应用于ReferenceEquals方法的结果。你怎么认为?还需要考虑可读性问题。ReferenceEquals在检查是否相等时看起来更清晰,但对于不等式,您可能会错过!在object.ReferenceEquals之前,第一个变体中的!=很难被忽略。使用object.ReferenceEquals方法是否有任何额外的开销否。该方法直接包含执行引用相等性检查的最小IL描述(记录:它等同于VB的Is运算符)并且通常由JIT内联(特别是在定位时x64),所以没有开销。关于可读性:我个人认为object.ReferenceEquals可能更具可读性(即使是否定形式),因为它阐明了它的语义。转换为对象可能会使一些程序员感到困惑。我刚找到一篇讨论这个的文章。它更喜欢(object)x==y因为IL占用空间较小。它认为使用这种与内联方法X的比较可能会有所帮助,但是(没有任何关于JIT的详细知识,但逻辑上和直觉上)我认为这是错误的:如果JIT的行为类似于优化C++编译器,它将考虑之后的方法内联对ReferenceEquals的调用,因此(对于内联)方法X)内存占用将完全相同。也就是说:选择一种方式而不是另一种方式对JIT和性能没有影响。与这里的答案相反,我发现(object)==比object.ReferenceEquals快。至于如何更快,很琐碎!Testbed:我知道你需要引用相等性检查,但我还包含了静态object.Equals(,)方法和它没有被覆盖的类。平台:x86;配置:发布版本classPerson{}publicstaticvoidBenchmark(Actionmethod,intiterations=10000){Stopwatchsw=newStopwatch();sw.开始();for(inti=0;i测试:Personp1=newPerson();Personp2=newPerson();boolb;Benchmark(()=>{b=(object)p1==(object)p2;//960~1000msb=object.ReferenceEquals(p1,p2);//~1250msb=object.Equals(p1,p2);//2100msb=EqualityComparer.Default.Equals(p1,p2);//~4000ms},100000000);Personp1=newPerson();Personp2=null;boolb;Benchmark(()=>{b=(object)p1==(object)p2;//990~1000msb=object.ReferenceEquals(p1,p2);//1230~1260msb=object.Equals(p1,p2);//1250~1300msb=EqualityComparer.Default.Equals(p1,p2);//~3100ms},100000000);Personp1=null;Personp2=null;boolb;Benchmark(()=>{b=(object)p1==(object)p2;//960~1000msb=object.ReferenceEquals(p1,p2);//1260~1270msb=object.Equals(p1,p2);//1180~1220msb=EqualityComparer.Default.Equals(p1,p2);//~3100毫秒},100000000);Personp1=newPerson();人p2=p1;布尔b;Benchmark(()=>{b=(object)p1==(object)p2;//960~1000msb=object.ReferenceEquals(p1,p2);//1260~1280msb=object.Equals(p1,p2);//1150~1200msb=EqualityComparer.Default.Equals(p1,p2);//3700~3800ms},100000000);object.Equals(,)内部调用了ReferenceEquals,如果不相等,就会调用类的overridevirtualEquals方法,所以会看到速度差异的通知Debug结果在配置中也是一致的...如指出,重点应放在可读性/意义/披露上。Object.ReferenceEquals的开销仅在参数加载时,在大多数情况下是JIT的。之后Object.ReferenceEquals和operator==都归结为单个ILceq运算符。在最坏的情况下,差异可以忽略不计。更重要的是,Object.ReferenceEquals比(object)o1==(object)o2更有意地揭示。它在代码中明确说明“我正在测试引用相等性/同一性”,而不是将意图隐藏在一堆演员表下。在经过长时间的关键代码(有时调用深度非常深)之后,在非常大的代码库中添加我的两分钱。JIT比现实世界的“微基准测试”有更多的问题和顾虑,而且它们具有编译时C++WPO的简单性,没有C#编译器更容易直接翻译,所有问题都没有。C#编译器完成后,它确实拥有所有上下文。'迂腐'形式:if((object)a==(object)b){}//ref等于if(!((object)a==(object)b)){}//ref不等于如果你真的在权衡和测量方面存在诚实的上帝性能问题,或者需要从JIT强调一些非常常见的类,这可以提供很多帮助。NullOrEmptyvs'(object)str==null||也str.Length==0'。没有WPO的奢侈,并且在许多情况下所有不知道的约束,在JITing命中后可能加载或卸载哪些程序集,在优化方面会发生奇怪的非确定性事情以及如何发生。这是一个很大的话题,但这里有几点:到目前为止,JIT将追逐内联和优化注册优化深度,这一切都取决于当时的其他情况。如果由于使用而最终在链上编译一次函数,并在链的另一端运行不同的函数,您可能会得到截然不同的结果。对于许多受延迟或UI驱动约束的应用程序,最糟糕的事情是去钝化,而在较大的应用程序中,这会很快加起来。!((对象)a==(对象)b)和(对象)a!=(object)b并不总是编译成相同的代码,因为!(a==b)和一个!=b,即使没有任何显式运算符或等于重写。一个'(对象)一个!=(object)b'更有可能触发.Net自己的更迂腐的调用运行时,这是非常昂贵的。即使您当前没有运算符或等于重写,如果对JIT非常有帮助,也要尽早保护它们,并且经常使用“(object)”或“RefEquals”。(对象)更好。如果你想想JIT必须做什么来确定一个类型是否可以被覆盖,并处理bizantine(sp)Equality规则等等,这就像一个迷你地狱,以及任何可以稍后公开的东西,你打算要引用相等性,您可以避免突然减速或稍后的代码。如果它已经是公开的而不是密封的,JIT不能保证规则会或有时间追查它们。保护通常更普遍的“无效”检查可能更重要,尽管这不是OP问题的一部分,因为通常适用相同的规则和关注点。'(object)a==null'和'!((object)a==null)'相当于'迂腐'。前面提到的关于更好的==运算符的文章提供了不完整的信息,至少在.NET4.0上是这样(好吧,它被写回了2.0时代)。它声明ReferenceEquals未优化/内联,只有在使用“AnyCPU”配置构建项目时才会出现这种情况。设置为'x86'或'x64'会使(object)obj==null和ReferenceEquals(object,null)以相同的IL结束,这两种方法都只是一个'ceq'IL指令。所以答案是:两种方法生成的IL在Release/x86或x64版本上是相同的。ReferenceEquals绝对更具可读性,至少对我来说是这样。publicstaticboolReferenceEquals(ObjectobjA,ObjectobjB){returnobjA==objB;}http://referencesource.microsoft.com/#mscorlib/system/object.cs,4d607d6d56a93c7e以上是C#学习教程:引用相等性能差异?((object)obj1==(object)obj2)vs.Object.ReferenceEquals(obj1,obj2)分享了全部内容,如果对你有用,需要进一步了解C#学习教程,希望大家多多关注---本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
