如何处理包含InvalidEnumArgumentException的代码维护?

8

我很好奇,如果你遇到了 System.ComponentModel.InvalidEnumArgumentException,你会如何维护你的代码。

基本上,我有一个像这样的 switch 语句:

switch (enumValue)
{
    case MyEnum.Value1:
        break;

    case MyEnum.Value2:
        break;

    default:
        throw new InvalidEnumArgumentException();
}

如果我决定在将来向MyEnum添加更多值,例如Value3Value4,那么怎么办?这意味着我最终会抛出一个误导性的异常。我该如何防止这种情况发生?
在抛出异常之前,我应该使用反射吗?在这种情况下,我应该抛出什么异常?我正在寻求建议。
我刚刚几分钟前才发现这个异常,所以也许我没有正确理解它的上下文。当某个枚举参数不受支持时(在这种情况下,Value3Value4将不被支持),是否会引发此异常?
6个回答

11

你提出的问题取决于上下文,如果一个方法接收一个枚举作为参数,它必须指定支持哪些值以及对未知的枚举值会做什么。

如果你添加更多的枚举选项,即使在默认情况下没有抛出异常,你也需要决定该怎么做。

请记住,异常非常有用,因为您可以将任何整数传递为枚举值。

例如:

enum Foo { A, B }

static int Bar(Foo f)
{
    switch (f)
    {
        case Foo.A:
            return 1;
        case Foo.B:
            return 2;
        default:
            throw new InvalidEnumArgumentException("f", (int)f, typeof(Foo));
    }
}

static void Main()
{
    Bar(Foo.A);
    Bar((Foo)99);
}

7
如果你的目标是 .NET 4.6 或更高版本,对这个示例进行轻微改进的方法是将 "f" 字符串替换为 nameof(f) - skkeeper

5
如果我决定在将来添加更多值到MyEnum中,例如Value3和Value4会怎样呢?那意味着我最终会抛出一个误导性的异常。我该如何防止这种情况发生?
当你使用InvalidEnumArgumentException时,关键要理解的是参数。通过抛出异常,你表明方法的参数是无效的。 (InvalidEnumArgumentException派生自ArgumentException)。它并不一定意味着该值不是枚举的成员。因此,我认为这并不会引起误导。

0
我不会在那种情况下使用你正在使用的异常。因为 enumValue 的类型是 MyEnum(我猜测?),它永远不可能包含无效的枚举值。如果您根据枚举值的值进行了切换,并且如果它们无法识别该值,则需要抛出适当的异常(也许只是普通的 ArgumentException ?),但在大多数情况下,我猜您会让代码运行未知的枚举值时什么都不做。

2
这是不正确的。根据设计指南的这个补充,“即使该值在枚举中未定义,将任何整数值转换为枚举都是合法的。”。 - Anders Fjeldstad
当然,一个 enum 值可以是无效的。你可以将不属于枚举值之一的数字转换为 enum 类型。或者这可能是由于在不同程序集中定义了一个枚举,并更新了扩展枚举。 - Allon Guralnek
1
哇,我从来没有想到。看起来今天我学到了新东西。 :-) - DoctorMick

0

4
那么应该抛出什么样的异常? - mbx
我会使用NotImplementedException - 因为我实际上没有实现任何代码来正确处理新添加的枚举值。 - Arno Peters

0

我相信你可能从错误的角度来看待这个问题。如果这些不是枚举类型,而是基于某些业务规则的特定值,那么在规则增加的情况下,你需要修改相关代码以包含新的规则。因此,如果你要修改枚举类型,你应该注意类似这样的变化。


如果有很多地方在使用相同的枚举进行 switch 语句操作,那么可以使用工厂根据枚举值创建多态对象,并将该功能从 switch 转移到该对象的方法中。 - driushkin

-1

为了验证传入的枚举值,请使用以下静态方法...

public void MyMethod(MyEnum e)
{
    if (!Enum.IsDefined(typeof(MyEnum), e))
        throw new InvalidEnumArgumentException("e", (int)e, typeof(MyEnum));

...而且如果未来增加了新的枚举值,您无需更改检查。


2
如果MyEnum被扩展了新的值,那么!Enum.IsDefined(typeof(MyEnum), e))将会对它们返回true,因此这个测试很可能永远不会失败。 - Spook
@Spook 但是如果MyEnum没有为0定义一个条目并且在MyEnum e; MyMethod(e);中e被隐式赋予默认值,或者当代码以数字方式设置e的值时,它将失败。关键是C#本身不强制e成为MyEnum的有效值,简单地说,您不能做出任何假设。 - binki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接