【问题标题】:Confusion about comparison by .Equals() vs. == operator and primitives vs. objects关于 .Equals() 与 == 运算符以及原语与对象的比较的混淆
【发布时间】:2018-03-31 11:00:01
【问题描述】:

考虑这段代码:

int a = 0;
short b = 0;
int c = 0;
object a1 = a;
object b1 = b;
object c1 = c;

Console.WriteLine(1);
//comparing primitives - int vs. short
Console.WriteLine(a == b);
Console.WriteLine(b == a);
Console.WriteLine(a.Equals(b));
Console.WriteLine(b.Equals(a));

Console.WriteLine(2);
//comparing objects - int vs. int
Console.WriteLine(c1 == a1);
Console.WriteLine(a1 == c1);
Console.WriteLine(c1.Equals(a1));
Console.WriteLine(a1.Equals(c1));

Console.WriteLine(3);
//comparing objects - int vs. short
Console.WriteLine(a1 == b1);
Console.WriteLine(b1 == a1);
Console.WriteLine(a1.Equals(b1)); //???
Console.WriteLine(b1.Equals(a1));

它打印这个输出:

1
True
True
True
False
2
False
False
True
True
3
False
False
False
False

我知道的;什么是明确的

第 2 节== 运算符仅在比较内存中由两个不同名称引用的一个对象时才会返回 true(不是很常见,但可能会发生)。 Equals() 方法比较对象的内容(值)。 这个网站的很多答案都提到了。

第 1 节:使用 == 运算符,编译器将“较小”类型转换为“较大”(shortint)并比较原始值。操作数(变量)的顺序无关紧要。最后一行中Equals() 的结果可能会令人困惑,因为它返回 false(不比较值),但可以理解。这里的顺序很重要。正如在此answer 中所了解的,必须选择最佳过载。它由第一个变量的类型选择:short.Equals(short)。但是int 无法转换为“较小”类型(short),因此没有进行比较并且方法返回 false。

问题:

  1. 我上面的理解正确吗?
  2. 为什么第 3 节的最后两行(使用 Equals())都返回 false?为什么第 1 节第 3 行有区别?为什么不进行重载和值比较?它变得非常抽象,我找不到原因。

【问题讨论】:

  • 它们返回 false 因为您在 Object 中有 boxed 值类型 int。这不是同一个实例(Object.Equals 使用 Object.ReferenceEquals)所以 Equals 返回 false。当一个值类型被装箱时,一个新的对象被分配和构造。
  • @TimSchmelter 注意(b.Equals(a)); 会给你假,没有装箱
  • @BRAHIMKamel:我已经回答了 OP 的第二个问题
  • @TimSchmelter 我认为这不是真的,因为object.Equals 是虚拟方法,所以在OP 情况下int.Equals 将被调用,而不是object.Equals
  • @BRAHIMKamel:b.Equals(a) 返回false 的原因是,如果类型不能隐式转换为shortint16.Equals 会调用Equals(Object)Int32 不是,所以它返回 false。如果您反转条件,您会得到true,因为short 隐式转换为int。阅读:docs.microsoft.com/en-us/dotnet/csharp/language-reference/…

标签: c# comparison equals


【解决方案1】:

在第 1 节第 3 行

int a = 0;
short b = 0;
Console.WriteLine(a.Equals(b));

你称这个int 的重载为:bool Equals(int other),因为b(短)可以隐式转换为int,所以选择了这个重载。它返回真。在第 3 节第 3 行

int a = 0;
short b = 0;
object a1 = a;
object b1 = b;
Console.WriteLine(a1.Equals(b1)); //???

int 的另一个重载(不是object,因为Equals 是虚方法)被调用:bool Equals(object other)。要让它返回 true,other 应该具有完全相同的类型 (int),但它实际上是 short,所以它返回 false。拳击在这里不相关,你可以用这个来验证:

int a = 0;            
int c = 0;
object a1 = a;
object c1 = c;
// yes, different objects
Console.WriteLine(a1 == c1); // false
// still equal, because both are boxed ints
Console.WriteLine(a1.Equals(c1)); // true

至于理解,我认为documentation 包含所有相关信息。请记住:

  1. == 运算符和Equals 方法都可以在类中手动定义,因此理论上可以做任何事情。您的理解仅与“默认”行为有关。

  2. == 在常识中不是虚拟的,不像Equals 方法。所以当你在编译时定义a1 == b1 - == 被调用时(基于a1b1 的类型),但是当你调用a1.Equals(b1) 时 - 它实际上是被调度的,所以调用方法是在运行时定义。

【讨论】:

    【解决方案2】:

    除了装箱意味着值类型将导致内存中的不同引用之外,您还必须考虑Implicit Numeric Conversions 事实上,出于这个原因,你有

    Console.WriteLine(a.Equals(b)); 
    

    这给你一个真实的 但不是这个

    Console.WriteLine(b.Equals(a));
    

    这里是另一个例子

    static void Main(string[] args)
            {
    
    
                int i = 0;
                long L = 0;
    
    
                Console.WriteLine(1);
                //comparing primitives - int vs. short
    
                Console.WriteLine(L.Equals(i)); //true
                Console.WriteLine(i.Equals(L));//false
            }
    

    【讨论】:

      猜你喜欢
      • 2019-12-29
      • 2018-04-01
      • 2020-11-04
      • 1970-01-01
      • 2012-03-04
      • 1970-01-01
      • 1970-01-01
      • 2017-01-24
      相关资源
      最近更新 更多