2

我今天遇到了一个有趣的情况:

var a = new HashSet<Object> { 1.0, 2.0, 3.0 };
a.Contains(1);     //False
a.Contains(1.0);   //True

当然,这只是一个通用版本:

Object b = 2.0;
b.Equals(2);            //False
b.Equals(2.0);          //True

我意识到这样做的原因是因为如果我编写2.0 == 2,C# 编译器会秘密地插入从整数到双精度的强制转换,并且通过使用 Object 中间体,编译器没有足够的信息来执行此操作。

我的问题是,运行时是否没有足够的信息来将整数提升一倍以进行比较?如果 C# 编译器认为隐式转换足够可取,为什么 JIT 不应该有类似的行为?

4

3 回答 3

4

C# 必须按照语言规范所说的方式工作。这与 Jitter 无关,它只需要实现语言规范。

C# 语言规范说明了==必须如何工作。

CLR 规范说明了Equals()必须如何工作。

实际上,.Net 1.1 和 .Net 2.0 之间发生了一个有趣的变化。

在 .Net 1.1 中,3f.Equals(3) == false.

在 .Net 2.0 中,3f.Equals(3) == true.

这与 . 的对象比较版本不同Equals()。向您展示这种事情是多么微妙。

一个有趣的(但很老的)博客在这里:http: //blogs.msdn.com/b/jmstall/archive/2005/03/23/401038.aspx

它实际上确实有一些与您的问题相关的细节,因此值得一读。

于 2013-05-21T22:22:40.613 回答
2

C# 是一种特定的编程语言,具有特定的处理语义2.0 == 2,在 ECMA-334 标准中定义。公共语言运行时 (CLR) 是由 ECMA-335 标准定义的执行环境,它在字节码上运行,而不是 C# 源代码。它们的语义在很多方面都不同,因此虽然可以实现运行时部分以自动为这些类型的比较执行扩展转换,但实际上并没有这样做。

这里做的具体比较恰好是调用Double.Equals(Object),返回

true如果obj是这个实例的一个实例Double并且等于这个实例的值;否则为假。

于 2013-05-21T22:22:15.873 回答
0

这感觉更像是一个社区问题,而不是一个寻找特定解决方案的问题。但我很乐意加入。

首先,我首先要说双重相等比较已经很危险,我相信您可能知道。有大量关于主题的信息

if(doubleNum == doubleNum2)

但还要考虑两个不同类型的不是亲戚的对象是否应该是平等的?在编写代码时,编译器可以假设一些基本的想法。但是大多数 .Equals(object) 方法做的第一件事是检查类型兼容性,如果它们不兼容,则返回 false。我会假设这里是这种情况,因为 b.Equals(2) 假设传递了一个不是双精度的 int 类型。

查看 double.Equals(object) 方法后,您会注意到它所做的第一件事是检查传递的对象是否为双精度对象。由于它是 Int32,因此该函数返回 false。

而其他答案更多的是实施的原因。上面应该解释为什么运行时的行为方式。

于 2013-05-21T22:16:11.343 回答