【问题标题】:Using an enum having entries with the same value of underlying type使用具有相同基础类型值的条目的枚举
【发布时间】:2014-10-12 03:18:42
【问题描述】:

如果我声明一个像这样的枚举

enum Weekdays
{
    Mon = 1,
    Tue = 1,
    Wen = 1,
    Thi,
    Fri,
    Sat,
    Sun
}

Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);//Prints Tue why?

现在如果我更改工作日并执行以下相同的操作

enum Weekdays
{
    Mon = 1,
    Tue = 1,
    Wen = 1,
    Thi = 1,
    Fri,
    Sat,
    Sun
}

Weekdays obj = (Weekdays)1;
Console.WriteLine(obj);//Prints Thi !!!!!How?

这里到底发生了什么?

【问题讨论】:

    标签: c# .net enums


    【解决方案1】:

    当你像这样写出你的值时,它最终会被 ToString() 调用。

    Console.WriteLine(obj);
    

    如果您深入研究代码,它会根据您的价值调用Enum.GetName()

    关于具有相同基础值的多个枚举值,MSDN 上的Enum.GetName 页面说:

    如果多个枚举成员具有相同的基础值,GetName 方法保证它将返回这些枚举成员之一的名称。但是,它不保证它总是返回同一个枚举成员的名称。因此,当多个枚举成员具有相同的值时,您的应用程序代码不应依赖于返回特定成员名称的方法。

    它没有说明如何在两个或更多的值相同时确定返回哪个名称。

    Enum.ToString() 的文档包含相同的警告,但措辞略有不同。

    再深入一点,上面的方法调用Array.BinarySearch,传递给它一个代表枚举中所有值的数字数组,以及一个代表你要打印的值的数字。

    因此,您有一个包含多个1 的数组,并且您正在搜索1。该调用的docs 类似:

    允许重复元素。如果 Array 包含多个等于 value 的元素,则该方法仅返回其中一个的索引,不一定是第一个。

    同样,它没有说明如何做出选择,只是说它不可靠。

    【讨论】:

    • 嘿,你能看看我的回答,告诉我这是否有意义吗?
    • @grant winney :: 实际上在这里 ToString() 或 Enum.GetName() 有什么用?
    • 我相信您得到响应的原因是因为各种值的哈希码:Mon=77548、Tue=84452、Wen=86848、Thi=84053。如果你只有 Mon、Tue 和 Wen = 1,那么二分搜索会在 Tue(它在中间)出现,但如果你添加 Thi = 1,那么你有 4 个项目,那么二分搜索将落在第二个元素上,这将是 Thi。
    【解决方案2】:

    当您分配相似的值时,结果会出乎意料,但我认为它会评估两种情况:

    当 n 为偶数时:

    (n/2)
    

    当 n 为奇数时:

    (n/2)+1
    

    如果我像这样更改enum

    enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1,Fri=1,Sat=1, Sun=1, Mon2=1, Mon3=1}
    // n is odd = 9
    // (n/2)+1 = 5
    
    Weekdays obj = (Weekdays)1;
    Console.WriteLine(obj);
    

    结果将是Fri,现在让我们再次更改enum

    enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1,Fri=1,Sat=1, Sun=1,Mon2=1}
    // n is even = 8
    // (n/2) = 4
    
    Weekdays obj = (Weekdays)1;
    Console.WriteLine(obj);
    

    结果现在是Thi,再次更改enum

    enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1,Fri=1,Sat=1, Sun=1}
    // n is odd = 7
    // (n/2)+1 = 4
    
    Weekdays obj = (Weekdays)1;
    Console.WriteLine(obj);
    

    结果现在是Thi,再次更改enum

    enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1,Fri=1,Sat=1}
    // n is even = 6
    // (n/2) = 3
    
    Weekdays obj = (Weekdays)1;
    Console.WriteLine(obj);
    

    结果现在是Wen,再次更改enum

    enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1,Fri=1}
    // n is odd = 5
    // (n/2)+1 = 3
    
    Weekdays obj = (Weekdays)1;
    Console.WriteLine(obj);
    

    结果现在是Wen,再次更改enum

    enum Weekdays {Mon=1,Tue=1,Wen=1,Thi=1}
    // n is even = 4
    // (n/2) = 2
    
    Weekdays obj = (Weekdays)1;
    Console.WriteLine(obj);
    

    结果现在是Tue,再次更改enum

    enum Weekdays {Mon=1,Tue=1,Wen=1}
    // n is odd = 3
    // (n/2)+1 = 2
    
    Weekdays obj = (Weekdays)1;
    Console.WriteLine(obj);
    

    结果现在是Tue

    尽管这完美地解释了这种行为,但这可能并不总是发生或可能不会发生,因为我没有检查更多情况,但正如 MSDN 所说,当 enum 具有相同的值时,您不应该假设这样的输出不同的名字...

    也就是说,我认为您现在可以轻松理解代码中发生了什么。

    参考:Link

    编辑:

    @GrantWinney 的回答让我想到了这一点,他写道,Array.BinarySearch 传递了值数组和要搜索的值,所以我从名称 Array.BinarySearch 意识到它肯定使用了 BinarySearch 并且解释一切......

    Binary Search 将像这样划分数组:

    Mid = {Low(which is the starting index) + High (which is the last index of array)}/2
    

    然后检查

    if (Mid == value) return index;
    else 
     if the value is smaller or equal move left other wise move right of the array
    

    所以这解释了如果 enum 值是您尝试打印的值的多个名称,它们是如何打印的。

    您的原始问题

    enum Weekdays
    {
        Mon = 1,
        Tue = 1,
        Wen = 1,
        Thi,
        Fri,
        Sat,
        Sun
    }
    
    Weekdays obj = (Weekdays)1;
    Console.WriteLine(obj);//Prints Tue why?
    

    它打印Tue,因为将通过数组调用Array.BinarySearch

    {1, 1, 1, 2, 3, 4, 5} 
    

    以及要搜索的值 1...

    所以BinarySearch 会这样做:

    Mid = {Low(0) + High(6)} / 2
    if (Mid == value) return index
    else move left 
    

    再次向左移动后,Mid 将被计算出来:

    High = Mid - 1; // now only the left sub-array will be searched
    Mid = {Low(0) + High(2)} / 2
    if (Mid == value) return index // here the condition will be true and you will be returned with `Tue`
    

    您的问题中的第二个示例:

    enum Weekdays
    {
        Mon = 1,
        Tue = 1,
        Wen = 1,
        Thi = 1,
        Fri,
        Sat,
        Sun
    }
    
    Weekdays obj = (Weekdays)1;
    Console.WriteLine(obj);//Prints Thi !!!!!How?
    

    正如我在上面写的那样,将调用Array.BinarySearch 和数组:

    {1, 1, 1, 1, 2, 3, 4} 
    

    将通过 value = 1 传递给搜索...

    在数组上应用BinarySearch 算法,它将评估为Thi

    【讨论】:

    • :在你的枚举中,如果我的枚举类似于enum WeekDays {Mon=1,Tue=1,Wen,Thi,Fri=1,sat,Sun }; WeekDays obj = (WeekDays)1; Console.WriteLine(obj);//prints fri,那么所有常量都具有相同的值,你能告诉我为什么吗?
    • 是的,我更改了它,因为我试图解释当枚举中的不同名称具有相同值时会发生什么。
    • @ShamseerKSmr 我还不能,但我已经写到我的答案中有一个模式,但不能 100%,因为它写在 MSDN 上,当枚举有输出时输出将是意外的不同名称的相同值...
    • 不知道尝试逆向工程 .Net 是如何做到这一点的。 .Net 不同版本中的实现可能会有所不同,Microsoft 可能会在未来版本中更改实现。然后是 Mono,以及(希望)将来会出现其他 C# 实现,每个实现都可能不同。
    • @SyedFarjadZiaZaidi :现在你说枚举肯定使用 BinarySearch 并解释了一切......如果我的枚举是这样的enum WeekDays { Mon=1, Tue=1, Wen, Thi, Fri=1, sat, Sun } 现在试试下面的代码WeekDays obj = (WeekDays)1; Console.WriteLine(obj);//print fri 你能解释一下吗为什么?根据您的解释,它必须打印 Tue 但不是。
    【解决方案3】:

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多