C#: Enum.TryParse() 在传递”-1″时成功,即使枚举不包含该值。

huangapple go评论70阅读模式
英文:

C#: Enum.TryParse() succeeds when passing "-1" even if the enum doesn't contain that value

问题

我想要仅在成功解析时打印枚举的值。如Enum.TryParse()文档中所述:
> 将一个或多个枚举常量的名称或数值的字符串表示形式转换为等效的枚举对象。返回值指示转换是否成功。

> 返回
布尔值
如果转换成功,则为true;否则为false

现在,考虑下面的示例,我期望只有在尝试解析像"first""1"这样的字符串时才成功,这些字符串是**TestEnum**的名称/值。

但是,如果尝试解析字符串"-1",调用仍然成功,并且我得到值-1这怎么可能呢?

示例:

using System;

public class HelloWorld
{
    public enum TestEnum
    {
        first = 0,
        second = 1,
        third = 2
    }
    
    public static void Main(string[] args)
    {
        TestEnum testEnum;
        bool res;
        
        res = Enum.TryParse("first", out testEnum);
        if (res)
            Console.WriteLine ("TEST 1 - res: " + res.ToString() + ", value: " + testEnum.ToString());
            
        res = Enum.TryParse("third", out testEnum);
        if (res)
            Console.WriteLine ("TEST 2 - res: " + res.ToString() + ", value: " + testEnum.ToString());
            
        res = Enum.TryParse("1", out testEnum);
        if (res)
            Console.WriteLine ("TEST 3 - res: " + res.ToString() + ", value: " + testEnum.ToString());
            
        
        res = Enum.TryParse("-1", out testEnum);
        if (res)
            Console.WriteLine ("TEST 4 - res: " + res.ToString() + ", value: " + testEnum.ToString());
            
        res = Enum.TryParse("fourth", out testEnum);
        if (res)
            Console.WriteLine ("TEST 5 - res: " + res.ToString() + ", value: " + testEnum.ToString());
    }
}

输出:

TEST 1 - res: True, value: first
TEST 2 - res: True, value: third
TEST 3 - res: True, value: second
TEST 4 - res: True, value: -1        // <-- How??

代码链接:https://onlinegdb.com/1MIOnOFl6

英文:

I want to print the value of an enum only if its gets parsed correctly. As stated in Enum.TryParse() docs:
> Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object. The return value indicates whether the conversion succeeded.

> Returns
Boolean
true if the conversion succeeded; false otherwise.

Now, considering the example below, I would expect that the call succeeds only if I try to parse strings like "first" or "1", which are name/values of TestEnum.

But if I try to parse the string "-1", the call still succeeds and I get -1 as value, how's that even possible??

Example:

using System;

public class HelloWorld
{
    public enum TestEnum
    {
        first = 0,
        second = 1,
        third = 2
    }
    
    public static void Main(string[] args)
    {
        TestEnum testEnum;
        bool res;
        
        res = Enum.TryParse("first", out testEnum);
        if (res)
            Console.WriteLine ("TEST 1 - res: " + res.ToString() + ", value: " + testEnum.ToString());
            
        res = Enum.TryParse("third", out testEnum);
        if (res)
            Console.WriteLine ("TEST 2 - res: " + res.ToString() + ", value: " + testEnum.ToString());
            
        res = Enum.TryParse("1", out testEnum);
        if (res)
            Console.WriteLine ("TEST 3 - res: " + res.ToString() + ", value: " + testEnum.ToString());
            
        
        res = Enum.TryParse("-1", out testEnum);
        if (res)
            Console.WriteLine ("TEST 4 - res: " + res.ToString() + ", value: " + testEnum.ToString());
            
        res = Enum.TryParse("fourth", out testEnum);
        if (res)
            Console.WriteLine ("TEST 5 - res: " + res.ToString() + ", value: " + testEnum.ToString());
    }
}

Output:

TEST 1 - res: True, value: first
TEST 2 - res: True, value: third
TEST 3 - res: True, value: second
TEST 4 - res: True, value: -1        // <-- How??

Link to the code: https://onlinegdb.com/1MIOnOFl6

答案1

得分: 6

实际上,枚举是一个整数,可以容纳所有普通整数可以容纳的值。在你的情况下,

TestEnum test1 = TestEnum.first;

将创建一个值为0的整数。但也可以创建一个变量

TestEnum test2 = (TestEnum)-1;

因为-1是一个有效的整数,可以赋给TestEnum。这也是你通常在使用枚举与开关语句时会这样写的原因:

switch(test)
{
   case TestEnum.first: DoSomething(); break;
   case TestEnum.second: DoSomethingElse(); break;
   case TestEnum.third: DoSomethingDifferent(); break;
   default: throw new Exception("test的值无效");
}

你需要默认子句,因为你不能确定你的枚举变量只是其中一个值:first、second或者third。

你也可以改变枚举的基础类型。例如,如果你像这样声明你的枚举:

public enum TestEnum : uint { first = 0, second = 1, third= 2}

上述的赋值将会是无效的(因为-1对于uint来说不是一个有效的值)。此外,res = Enum.TryParse("-1", out testEnum);在这种情况下会返回false。

如果你想知道为什么这样的行为是有意义的,考虑带有标志选项的枚举:

[Flags]
public enum Options
{
None = 0,
Option1 = 1,
Option2 = 2,
Option3 = 4,
Option4 = 8
}

在这里,你可以写Options options = Options.Option1 | Options.Option2,它的值是3,而在上面的枚举中并没有定义。

正如评论中所述,如果你想检查值是否真的已定义,你可以使用Enum.IsDefined方法。你可以检查数值或字符串在你的枚举中是否已定义。

英文:

Actually, an enum is an integer and can hold all values a normal integer can hold. In your case,

TestEnum test1 = TestEnum.first;

will create an integer of value 0. But it is also possible to create a variable

TestEnum test2 = (TestEnum)-1;

Because -1 is a valid integer and can be assigned to TestEnum. This is also the reason why you typically write code like this if you use a switch with an enum:

switch(test)
{
   case TestEnum.first: DoSomething(); break;
   case TestEnum.second: DoSomethingElse(); break;
   case TestEnum.third: DoSomethingDifferent(); break;
   default: throw new Exception("invalid value for test");
}

You need the default clause because you can not rely that your enum variable is only one of the values first, second or third.

You can also change the underlying type of your enum. For example, if you declare your enum like

public enum TestEnum : uint { first = 0, second = 1, third= 2}

The assignement above will be invalid (because -1 is not a valid value for uint. Also, res = Enum.TryParse("-1", out testEnum); will return false in that case.

If you wonder why such a behaviour can make sense, consider enums with flags option:

[Flags]
public enum Options
{
None = 0,
Option1 = 1,
Option2 = 2,
Option3 = 4,
Option4 = 8
}

Here you can write Options options = Options.Option1 | Options.Option2, which has the value 3 which is not defined in the enum above.

As noted in the comments, you can use the Enum.IsDefined method if you want to check whether the value is really defined. You can check whether the numeric value or the string is defined in your enum.

huangapple
  • 本文由 发表于 2023年7月7日 05:28:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76632619.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定