【问题标题】:Object == equality fails, but .Equals succeeds. Does this make sense? [duplicate]Object == 相等失败,但 .Equals 成功。这有意义吗? [复制]
【发布时间】:2012-09-28 07:45:51
【问题描述】:

可能重复:
Difference between == operator and Equals() method in C#?

两种形式的相等,第一种失败,第二种成功。

(object)"abc" == (object)"abc"
false

((object)"abc").Equals((object)"abc")
true

在下面的参考资料中,我们看到“C# 中的等式运算符不是多态的”

参考:String Equality operator == in c#

顺便说一句:仍然不确定为什么这是一个问题。我以为可能是这样的,但不是因为这次测试成功了。

    static void Main(string[] args) {
        var o = new classOfT<string>() { val = "abc" };
        Console.WriteLine((object)o.val == "abc");
    }

    public class classOfT<T> {
        public string val { get; set; }
    }

顺便说一句:我不同意关于这个问题的完全相同的规则,但是,嘿。

答案是:

... String 类同时包含一个静态 bool Equals(string a, string b) 方法和静态 bool Equals(object a, object b) 方法。 不同的是前者是在 String 类中定义的 本身,而后者继承自 Object 类(即 String 的基类)

这在语义上是有道理的,但在更广泛的 OO 和 C# 语言环境中是否有意义?

我为什么要为这个问题烦恼?好吧,刚刚发现了一个错误,我想在我的脑海中将其归档在押韵或理由下,而不是在“记住这个”下,它在类别之前被咬了。

更新:

目前正在考虑使用原语(从功能角度)与多态性。由于我一直在做越来越多的功能性东西,这可能就是为什么母语让我感到困惑。我还没有考虑完这个(不,我不务实。我被语言设计所吸引)。感谢大家的回复!

【问题讨论】:

  • 我不是 C# 大师,但似乎第一行是比较对象,它们在内存中是不同的,这就是它失败的原因 - 第二行是比较实际值 'abc'这是平等的,这就是为什么它是真的。
  • @BurhanKhalid 你是对的。字符串对象的 equals 方法将比较存储在对象内部的字符串值。而两个不同的对象引用永远不会相等。
  • 有趣的是,在 LINQPad 中 (object)"abc" == (object)"abc" 返回 True
  • (object)"abc" == (object)"abc" 返回true。想一想,你现在的文化是什么?
  • @Habib:我会进一步调查。 .net 版本是 4。很高兴(也很困惑)它在其他地方直观地按预期工作。谢谢你告诉我。

标签: c# .net


【解决方案1】:
(object)"abc" 

将从字符串对象创建一个对象引用。原来如此

(object)"abc" == (object)"abc"

将创建两个不相等的对象引用。

但是,使用 equals 方法会检查存储的字符串的值是否相等。同样,这不是所有对象的默认实现,而是 String 对象的默认实现。对于任何自定义对象,您应该定义自己的 equals 方法的自定义实现来实现此行为。

【讨论】:

  • 你没有创建两个对象引用,你只是告诉编译器你想比较这两个值,就好像它们都是object类型一样默认情况下,比较引用。
  • 您根本没有创建两个对象 - 字符串文字被保留,因此您正在比较两个相等的引用。由于对 object 的强制转换,只使用了引用比较,但由于它们是对同一对象的两个引用,所以比较将返回 true。
【解决方案2】:

代码示例返回 true。

(object)"abc" == (object)"abc"

我认为您提供的示例与应用程序中返回 false 的代码不同。 CLR 使用字符串实习进行字符串优化。转换为 System.Object 将导致 == 运算符比较引用,并且由于字符串实习功能,== 运算符将导致 true。只有当 == 运算符两边的参数都引用堆上不同的字符串对象时,比较才会返回 false。

检查程序集是否已标记[assembly: CompilationRelaxations(System.Runtime.CompilerServices.CompilationRelaxations.NoStringInterning)] 属性。

【讨论】:

  • 虽然在那种特殊情况下,我不认为它是允许这是真的实习,但事实上它们都是具有相同值的字符串文字,然后编译器将优化以使用相同的字符串实例。
  • @JeffMercado: 转换为 System.Object 然后使用 == 运算符与使用 Object.ReferenceEquals 方法本质上是一样的,只有当 == 运算符的两边都引用时,输出才会为真相同的堆实例。我知道的与字符串相关的唯一编译器优化是字符串实习。可能还有其他人,但我不知道他们。我认为 OP 在不同的代码中存在问题,并在问题中提供了不同的示例。然而,OP 可能会验证这不是字符串实习的情况。
  • @jags,字符串常量始终是同一个对象。参见stackoverflow.com/a/4286639/892327,它引用了csharpindepth.com/Articles/Strings
【解决方案3】:

== operator

对于预定义的值类型,相等运算符 (==) 在以下情况下返回 true 其操作数的值相等,否则为假。以供参考 字符串以外的类型,如果两个操作数引用 ==,则返回 true 同一个对象。对于字符串类型,== 比较 字符串。

Equals

被字符串类覆盖,如果 obj 是 字符串及其值与本实例相同;否则为假。”

如果您的代码如下所示,

var s1= GetString1(); //some string object
var s2= GetString2(); //some string object containing same content as s1

(object)s1 == (object)s2
returns false - because == compares the references of the objects (which will be different if not interned)

((object)s1).Equals((object)s2)
returns true - because Equals will be called between actual strings at run time

但是,在当前形式中,您的代码

(object)"abc" == (object)"abc"
((object)"abc").Equals((object)"abc")

在这两种情况下都应该返回 true,因为具有相同值的字面量字符串在默认情况下会被实习,因此引用相同的对象(即引用也是相等的)

【讨论】:

    【解决方案4】:

    字符串比较应该通过String.Compare完成,

    http://blogs.msdn.com/b/abhinaba/archive/2005/10/28/486173.aspx

    http://msdn.microsoft.com/en-US/vstudio/aa496123?pull=/library/en-us/dndotnet/html/StringsinNET20.asp

    我不认为您“发现了错误”,因为 Microsoft 在 .NET BCL 中多次这样做,并且它变得很常见,我们作为开发人员必须适应。一个简单的例子是,

    var ip1 = IPAddress.Parse("127.0.0.1");
    var ip2 = IPAddress.Parse("127.0.0.1");
    

    你会找到ip1 != ip2,但是ip1.Equals(ip2) == true。推荐的比较方法是IPAddress.Compare(ip1, ip2)。无论如何,有时你必须记住一些事情。

    【讨论】:

      猜你喜欢
      • 2013-05-26
      • 1970-01-01
      • 2019-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多