Enum.Parse返回意外成员

lar*_*z11 9 c#

考虑以下代码:

namespace ConsoleApplication1 {
class Program {
    public static void Main (string[] args) {
        var en = (TestEnum)Enum.Parse(typeof(TestEnum), "AA");
        Console.WriteLine(en.ToString());
        Console.ReadKey();
    }
}

public enum TestEnum {
    AA = 0x01,
    AB = 0x02, 
    AC = 0x03,
    BA = 0x01,
    BB = 0x02,
    BC = 0x03
}
}
Run Code Online (Sandbox Code Playgroud)

如果执行此操作,变量en将获得值TestEnum.BA.现在我从中学到了枚举标志应该是唯一的,或者你得到这些意想不到的东西,但我确实不明白这里发生了什么.

更奇怪的部分是,当我将[Flags]属性添加到TestEnum时,它解决了问题并返回TestEnum.AA而不是TestEnum.BA,但对于原始枚举(更大,约200个成员)我发现这个问题这没有什么区别.

我的理解是枚举是一种值类型,所以当你定义自己的标志时,它会将内存中的值存储为0x01(对于TestEnum.AA),当你将它从对象转换为TestEnum时,它将执行查找那个标志值并找到TestEnum.BA.

运行以下行也可以确认这一点:

var en = (TestEnum)(object)TestEnum.AA;
Console.WriteLine(en.ToString());
Run Code Online (Sandbox Code Playgroud)

哪个会输出: BA

所以我的问题是:这到底发生了什么?更重要的是,为什么添加Flags属性会有所不同?

Mat*_*son 12

首先,这与此无关Enum.Parse().默认情况下int,枚举的基础类型是,因此在您的示例中TestEnum.AA,TestEnum.BA它们都存储为,1并且无法区分它们.

见以下代码:

Console.WriteLine(TestEnum.AA); // Prints BA
Console.WriteLine(TestEnum.BA); // Prints BA
Run Code Online (Sandbox Code Playgroud)

其次,设置[Flags]属性改变输出的原因是因为在确定字符串时采用了不同的代码路径.

这是ReferenceSource的代码:

private static String InternalFormat(RuntimeType eT, Object value)
{
    if (!eT.IsDefined(typeof(System.FlagsAttribute), false)) // Not marked with Flags attribute
    {
        // Try to see if its one of the enum values, then we return a String back else the value
        String retval = GetName(eT, value);
        if (retval == null)
            return value.ToString();
        else
            return retval;
    }
    else // These are flags OR'ed together (We treat everything as unsigned types)
    {
        return InternalFlagsFormat(eT, value);

    }
}
Run Code Online (Sandbox Code Playgroud)

注意GetName()如果[Flags]未设置则调用如何调用,否则InternalFlagsFormat()调用.

最终执行GetName()二进制搜索以找到值,而InternalFlagsFormat()最终执行线性搜索以查找值.

InternalFlagsFormat()必须进行线性搜索,因为它可能需要设置多个值(例如"X | Y | Z"),因此Microsoft为它实现了O(N)解决方案.然而,GetName()他们寻求更高效的O(Log2(N))解决方案.

二元搜索可以(并且确实)找到与线性搜索不同的重复值,因此存在差异.