List.Any()在预期为false时返回true

时间:2016-10-14 08:31:28

标签: c# linq

我们今天在代码中遇到了一个错误。我们有几个列表,其中数据的关键是枚举。有多个不同的枚举用作键(下面的代码中的Foo.Bar1和Foo.Bar2)。

所有测试都有一个包含1个项目的DataField列表,其中键设置为其中一个枚举值。第一次和最后一次测试按预期运行。第二次测试预计会成功,但失败了。阅读代码时似乎是合法的。

我的假设是,通过取消装箱变量,将枚举值转换为整数值并进行比较。这使它们相等,从而返回true,从而使Any()方法也返回true。它是否正确?或者还有其他事情发生了吗?

我们应该在第三次测试中使用equals()方法编写比较...

如果在下面的单元测试中重新创建了一个非常简化的问题版本。

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Linq;

namespace EnumCastTest
{
    [TestClass]
    public class UnitTest1
    {
        public class DataField
        {
            public Enum Key { get; set; }
        }

        class Foo
        {
            public enum Bar1 { A }
            public enum Bar2 { B }
        }


        [TestMethod]
        public void Field_With_Bar1_A_Should_Return_True()
        {
            List<DataField> fields = new List<DataField> {
                new DataField() { Key = Foo.Bar1.A} };

            Assert.IsTrue(fields.Any(q => (Foo.Bar1)q.Key == Foo.Bar1.A));
        }

        [TestMethod]
        public void Field_Without_Bar1_A_Should_Return_False()
        {
            List<DataField> fields = new List<DataField> {
                new DataField() { Key = Foo.Bar2.B} };

            Assert.IsFalse(fields.Any(q => (Foo.Bar1)q.Key == Foo.Bar1.A));
        }

        [TestMethod]
        public void Field_Without_Bar1_A_Should_Return_False2()
        {
            List<DataField> fields = new List<DataField> {
                new DataField() { Key = Foo.Bar2.B} };

            Assert.IsFalse(fields.Any(q => Foo.Bar1.A.Equals(q.Key)));
        }
    }
}

4 个答案:

答案 0 :(得分:8)

这是因为以下内容返回true:

var x = Foo.Bar1.A;
var y = (Foo.Bar2)x;
Console.WriteLine(y == Foo.Bar2.B);

枚举在内部由整数值表示,默认情况下使用的类型为is an int

  

每个枚举类型都有一个基础类型,除了char之外,它可以是任何整数类型。枚举元素的默认基础类型是int。

将一个枚举类型转换为另一个枚举类型时使用此基础类型。因此,对于枚举值,正在使用整数值,然后在此基础上创建新的枚举值。

基本上,这个过程是这样的:

var x = Foo.Bar1.A;
int integral = (int)x;
var y = (Foo.Bar2)integral;

除非您明确指定每个枚举成员的数字,否则默认情况下,枚举声明中的位置决定从0开始的整数值。

因此,在上面的示例中,integral将为0,因为Bar1.ABar1的第一个成员。 Bar2的第一个成员是Bar2.B,这就是你得到的结果。

因此测试失败的原因是因为在将一个枚举转换为另一个类型时,类型标识将丢失。通常,枚举仅在其自己的域中具有真正意义,即当您将一个成员与同一枚举的另一个成员进行比较时。

答案 1 :(得分:0)

我想,每个枚举都会转换为它的基础类型 - Int32。当你没有为每个人设定值时,他们假设为零。

答案 2 :(得分:0)

您将Foo.Bar2枚举设置为值B,并且您要检查Foo.Bar1枚举值A. 尝试检查正确的枚举。 如下面的代码所示:

new DataField() { Key = Foo.Bar1.B} };

        Assert.IsFalse(fields.Any(q => (Foo.Bar1)q.Key == Foo.Bar1.A));

答案 3 :(得分:0)

我想你希望enum值和类型相同,Any(...)返回true。

    [TestMethod]
    public void Field_Without_Bar1_A_Should_Return_False()
    {
        List<DataField> fields = new List<DataField> {
            new DataField() { Key = Foo.Bar2.B} };

        Assert.IsFalse(fields.Any(q => (q.Key is Bar1) && (Foo.Bar1)q.Key == Foo.Bar1.A));
    }

如果第一个谓词为真,则评估第二个谓词。