我不了解我的处境。下面是简化的情况:
list1 = [['a','b'],['c','d']]
[{"name": x[0], "value": x[1]} for x in list1]
我不明白为什么一个表达会使我成为事实,而另一个使我成为错误。它们看起来完全一样。
答案 0 :(得分:14)
您完全可以发现这令人困惑。真是一团糟。
首先,通过查看更多示例清楚地说明发生的情况,然后我们将推断出此处应用的正确规则。让我们扩展程序以考虑所有这些情况:
double d = 2;
double? nd = d;
int i = 2;
int? ni = i;
Console.WriteLine(d == d);
Console.WriteLine(d == nd);
Console.WriteLine(d == i);
Console.WriteLine(d == ni);
Console.WriteLine(nd == d);
Console.WriteLine(nd == nd);
Console.WriteLine(nd == i);
Console.WriteLine(nd == ni);
Console.WriteLine(i == d);
Console.WriteLine(i == nd);
Console.WriteLine(i == i);
Console.WriteLine(i == ni);
Console.WriteLine(ni == d);
Console.WriteLine(ni == nd);
Console.WriteLine(ni == i);
Console.WriteLine(ni == ni);
Console.WriteLine(d.Equals(d));
Console.WriteLine(d.Equals(nd));
Console.WriteLine(d.Equals(i));
Console.WriteLine(d.Equals(ni)); // False
Console.WriteLine(nd.Equals(d));
Console.WriteLine(nd.Equals(nd));
Console.WriteLine(nd.Equals(i)); // False
Console.WriteLine(nd.Equals(ni)); // False
Console.WriteLine(i.Equals(d)); // False
Console.WriteLine(i.Equals(nd)); // False
Console.WriteLine(i.Equals(i));
Console.WriteLine(i.Equals(ni));
Console.WriteLine(ni.Equals(d)); // False
Console.WriteLine(ni.Equals(nd)); // False
Console.WriteLine(ni.Equals(i));
Console.WriteLine(ni.Equals(ni));
除了我标记为打印为假的那些以外,所有这些都打印为真。
我现在将对这些情况进行分析。
首先要注意的是==
运算符总是说True
。为什么会这样?
不可为空的==
的语义如下:
int == int -- compare the integers
int == double -- convert the int to double, compare the doubles
double == int -- same
double == double -- compare the doubles
因此,在每种非空值情况下,整数2等于double 2.0,因为int 2转换为double 2.0,并且比较结果为true。
可为空的==
的语义是:
同样,我们看到对于可空比较,int? == double?
,int? == double
,依此类推,我们总是退回到非可空情况,将int?
转换为{ {1}},并进行双精度比较。因此,这些也都是正确的。
现在我们来到double
,这是混乱的地方。
这里有一个基本的设计问题,我在2009年就写过:https://blogs.msdn.microsoft.com/ericlippert/2009/04/09/double-your-dispatch-double-your-fun/-问题是Equals
的含义是根据两者的编译时间类型来解决的操作数。但是==
是根据 left 操作数(接收方)的运行时类型解析的,而基于编译时间类型 right 操作数(参数)的>,这就是为什么事情出轨的原因。
让我们开始看看Equals
的作用。如果对double.Equals(object)
的呼叫的接收者为Equals(object)
,则如果参数不是黑框,则认为它们不相等。也就是说,double
要求类型 match ,而Equals
要求类型可以转换为通用类型。
我再说一遍。与==
不同,double.Equals
不会 尝试将其参数转换为double。它只是检查是否已经是的两倍,如果不是,则表示它们不相等。
然后说明了为什么==
是错误的...但是...请稍等,上面的不是错误!是什么原因解释了?
d.Equals(i)
已超载!上面我们实际上是在调用double.Equals
,您猜对了,它会在进行调用之前将int转换为double!如果我们说过double.Equals(double)
,那将是错误的。
好的,所以我们知道为什么d.Equals((object)i))
是正确的-因为int转换为double。
我们也知道为什么double.Equals(int)
为假。 double.Equals(int?)
不能转换为double,但是可以转换为int?
。因此,我们称object
并在double.Equals(object)
框内输入,现在不相等。
int
呢?的语义是:
nd.Equals(object)
的不可为空的语义因此,我们现在知道如果d.Equals(object)
是nd.Equals(x)
或x
的情况下double
起作用的原因,但是如果是double?
或int
则为什么int?
起作用。 (尽管有趣的是,(default(double?)).Equals(default(int?))
当然是正确的,因为它们都为空!)
最后,通过类似的逻辑,我们了解了int.Equals(object)
为什么给出其行为。它检查其参数是否为装箱的int,如果不是,则返回false。因此i.Equals(d)
为假。 i
无法转换为double,d
无法转换为int。
这真是一团糟。我们希望平等是一个对等关系,事实并非如此!平等关系应具有以下属性:
==
是正确的,但对A.Equals(B)
而言并非如此。因此,在所有级别上都是一团糟。 ==
和Equals
具有不同的调度机制并给出不同的结果,它们都不是等价关系,并且始终令人困惑。抱歉让您陷入困境,但是当我到达时真是一团糟。
要对C#中的平等为何如此糟糕的原因有一些不同的看法,请参阅我的令人遗憾的语言决定列表中的第9个项目,这里:http://www.informit.com/articles/article.aspx?p=2425867
奖金练习:重复以上分析,但对于x?.Equals(y)
可为空的情况,请重复x
。什么时候获得与非空接收器相同的结果,什么时候获得不同的结果?
答案 1 :(得分:1)
每种类型的Equals
方法的答案似乎都在答案中。如果类型不匹配,则它们不相等。
https://referencesource.microsoft.com/#mscorlib/system/double.cs,147
// True if obj is another Double with the same value as the current instance. This is
// a method of object equality, that only returns true if obj is also a double.
public override bool Equals(Object obj) {
if (!(obj is Double)) {
return false;
}
double temp = ((Double)obj).m_value;
// This code below is written this way for performance reasons i.e the != and == check is intentional.
if (temp == m_value) {
return true;
}
return IsNaN(temp) && IsNaN(m_value);
}
https://referencesource.microsoft.com/#mscorlib/system/int32.cs,72
public override bool Equals(Object obj) {
if (!(obj is Int32)) {
return false;
}
return m_value == ((Int32)obj).m_value;
}