我们今天在代码中遇到了一个错误.我们有几个列表,其中数据的关键是枚举.有多个不同的枚举用作键(下面的代码中的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)));
}
}
}
Run Code Online (Sandbox Code Playgroud)
发生这种情况是因为以下内容返回true
var x = Foo.Bar1.A;
var y = (Foo.Bar2)x;
Console.WriteLine(y == Foo.Bar2.B);
Run Code Online (Sandbox Code Playgroud)
枚举在内部由整数值表示,默认情况下使用的类型是int:
每个枚举类型都有一个基础类型,除了char之外,它可以是任何整数类型.枚举元素的默认基础类型是int.
将一个枚举类型转换为另一个枚举类型时使用此基础类型.因此,对于枚举值,正在使用整数值,然后在此基础上创建新的枚举值.
从本质上讲,这个过程是这样的:
var x = Foo.Bar1.A;
int integral = (int)x;
var y = (Foo.Bar2)integral;
Run Code Online (Sandbox Code Playgroud)
除非您使用每个枚举成员明确指定数字,否则默认情况下,枚举声明中的位置将决定整数值,以0.开头.
所以在上面的例子中,integral将是0,因为Bar1.A是第一个成员Bar1.而第一个成员Bar2是Bar2.B,所以这就是你得到的结果.
因此测试失败的原因是因为在将一个枚举转换为另一个类型时,类型标识将丢失.通常,枚举只在自己的域中产生真正意义,即当您将一个成员与同一枚举的另一个成员进行比较时.