.Net、C# - Boolean.Equal 不同于 == 比较

.Net, C# - Boolean.Equal differs from == compare

我们正在使用 AutoMapper 从 IDataReader 映射到实体列表。

我在单元测试时注意到的一个问题如下。如果我们从数据库(位)中读取一个 bool 值,AutoMapper 会很好。但是当我们使用 FluentAssertions 进行单元测试时,ShouldAllBeEquivalentTo 函数出现了问题。它说 True expected 但 True 在实体的 bool 属性 上返回。

所以我尝试检查 bool 属性并注意到 expected == returnd 有效 (returns true) 但 expected.Equals(returned) 无效 (returns false)?!

我觉得==equals对于bool类型应该差不多吧?

什么会导致这种奇怪的行为?

这里是一些代码:

using (var connection = new SqlConnection("server=someServer;user id=someUser;password=***;database=someDatabase;MultipleActiveResultSets=True"))
using (var command = connection.CreateCommand())
{
    connection.Open();

    var itemsBefore = new List<Item> { new Item { CheckDispo = true } };

    command.CommandText = "SELECT CheckDispo FROM Items WHERE ItemId = 1814";
    var itemsAfter = Mapper.DynamicMap<List<Item>>(command.ExecuteReader());

    var a = itemsAfter[0].CheckDispo.Equals(true); // false
    var b = itemsAfter[0].CheckDispo == true; // true
}

public class Item
{
    public bool CheckDispo { get; set; }
}

两个结果都应该 return 正确。 我已经在上面测试了您的相同场景,并且在这两种情况下都是 return true 。请看下面的截图。

布尔值 class 重写 Equals 方法如下:

 public override bool Equals(object obj)
        {
            if (!(obj as bool))
            {
                return false;
            }
            return this == (bool)obj;
        }

它还提供了一个单独的重载方法,它接受一个布尔值作为参数。这仅使用相等运算符。我认为这是添加的,因为它提供了比 Equals 方法更好的性能,因为它避免了类型转换开销。

public bool Equals(bool obj)
        {
            return this == obj;
        }

在你的情况下,因为你传递的是一个布尔值,它应该使用上面的重载方法,正如你所看到的,它只是使用 === 运算符。

很抱歉这么晚的编辑,但我发现出了什么问题。我们从数据库中读取了 属性,而我们的 'boolean' 由 -1 而不是 1 表示。 Automapper 使用动态生成的 IL 代码从数据读取器读取数据,因为这样做,automapper 能够将 -1 写入 bool 字段。这导致 out RAM 中的值为 0xff。 如果我们现在查看 equals 方法的 il 代码,那么我们就会明白 wy .equal 不是 ==.

.method public hidebysig newslot virtual final 
        instance bool  Equals(bool obj) cil managed
{
  .custom instance void __DynamicallyInvokableAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       6 (0x6)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldind.u1
  IL_0002:  ldarg.1
  IL_0003:  ceq
  IL_0005:  ret
} // end of method Boolean::Equals

这会将 1 和我们的值加载到堆栈并比较两者。由于在我们的 RAM 中 bool 是 -1 (0xFF) 比较将 return false.

有关详细信息,另请参阅 github.com 上的此项。