代码之家  ›  专栏  ›  技术社区  ›  Jon Skeet

无效泛型类型参数的最佳异常

  •  95
  • Jon Skeet  · 技术社区  · 15 年前

    我正在写一些代码 UnconstrainedMelody 它有与枚举相关的泛型方法。

    现在,我有了一个静态类,其中包含一系列方法 只有 用于“flags”枚举。我不能将此添加为约束…因此,也可能使用其他枚举类型调用它们。在这种情况下,我想抛出一个异常,但我不确定该抛出哪个异常。

    如果我有这样的东西:

    // Returns a value with all bits set by any values
    public static T GetBitMask<T>() where T : struct, IEnumConstraint
    {
        if (!IsFlags<T>()) // This method doesn't throw
        {
            throw new ???
        }
        // Normal work here
    }
    

    最好的例外是什么? ArgumentException 听起来很合理,但这是 类型 争论,而不是正常的争论,这很容易混淆事情。我应该介绍一下我自己的吗 TypeArgumentException 班级?使用 InvalidOperationException ? NotSupportedException ?还有别的吗?

    我想要 相当地 除非这显然是正确的做法,否则不要为这件事创建我自己的例外。

    11 回复  |  直到 7 年前
        1
  •  42
  •   Community CDub    7 年前

    NotSupportedException 声音 很显然,它是合适的,但是文档清楚地表明,它应该用于不同的目的。从msdn类备注:

    有些方法没有 在基类中支持, 期望这些方法 在派生类中实现 相反。派生类可能 只实现方法的一个子集 从基类,然后抛出 不支持的例外 不支持的方法。

    当然,有一种方法 冒号 显然足够好,特别是考虑到它的常识意义。说了这些,我不确定是否正确。

    鉴于 Unconstrained Melody

    有很多有用的事情可以用普通的 存在“t:enum”或“t: 代表“—但不幸的是,这些在C中是被禁止的。

    这个实用程序库使用ildasm/ilasm来绕过禁令…

    …好像是新的 Exception 尽管在创造习俗之前,我们必须要面对很高的举证责任,但这可能是合理的。 Exceptions . 类似的东西 InvalidTypeParameterException 可能在整个库中都有用(或者不有用——这肯定是一个边缘案例,对吧?).

    客户是否需要将其与BCL异常区分开来?客户什么时候会不小心用香草精打电话给这个? enum ?你如何回答被接受的答案所提出的问题? What factors should be taken into consideration when writing a custom exception class?

        2
  •  23
  •   JaredPar    15 年前

    我会避免不支持例外。此异常在未实现方法且有一个属性指示不支持此类型操作的框架中使用。它不适合这里

    我认为invalidOperationException是您可以在这里抛出的最合适的异常。

        3
  •  12
  •   l33t    7 年前

    对于无效的类型参数,不应在运行时引发泛型编程。它不应该编译,您应该有一个编译时强制。我不知道什么 IsFlag<T>() 包含,但也许您可以将其转换为编译时强制,例如尝试创建只能使用“flags”创建的类型。也许是 traits 类可以帮助。

    更新

    如果你 必须 抛出,我投票赞成InvalidOperationException。原因是泛型类型 参数 与(方法)参数相关的错误集中在ArgumentException层次结构周围。然而, recommendation 关于争论,例外情况是

    如果故障不涉及 争论本身,那么 InvalidOperationException应为 使用。

    至少有一次信仰的飞跃,那就是 方法 参数建议也适用于 通用的 参数,但在系统中没有更好的例外层次结构imho。

        4
  •  9
  •   Robban    15 年前

    我会用不支持的例外,因为这就是你所说的。除特定枚举以外的其他枚举是 不支持 . 当然,这将在异常消息中更清楚地说明。

        5
  •  8
  •   Mehrdad Afshari    15 年前

    我会去 NotSupportedException . 同时 ArgumentException 看起来不错,当传递给方法的参数是不可接受的时候,这确实是意料之中的。类型参数是要调用的实际方法的定义特征,而不是真正的“参数”。 InvalidOperationException 当您正在执行的操作在某些情况下是有效的,但在特定情况下是不可接受的时,应该抛出。

    冒号 当操作本身不受支持时引发。例如,在实现一个特定成员对类没有意义的接口时。类似的情况。

        6
  •  3
  •   Carl Bergquist    15 年前

    我不支持扩展。

        7
  •  3
  •   Alice    9 年前

    显然,微软使用 ArgumentException 为此,如以下示例所示: Expression.Lambda<> , Enum.TryParse<> Marshal.GetDelegateForFunctionPointer<> 在例外部分。我也找不到任何指示相反的例子(尽管搜索本地参考源 TDelegate TEnum )

    所以,我认为至少在Microsoft代码中,可以安全地假定使用 参数异常 对于基本变量之外的无效泛型类型参数。考虑到中的异常描述 docs 不区分这些,也不算太过分。

    希望它能一劳永逸地解决问题。

        8
  •  2
  •   Eric Schneider    15 年前

    在任何有问题的情况下,都应该抛出定制的异常。不管API用户需要什么,自定义异常总是可以工作的。如果开发人员不关心,他可以捕获任何一种异常类型,但是如果开发人员需要特殊处理,他将是sol。

        9
  •  1
  •   BFree    15 年前

    从NotSupportedException继承如何?虽然我同意@mehrdad的说法,但我听到你的观点,它似乎并不完美。所以继承自NotSupportedException,这样,针对API进行编码的人仍然可以捕获NotSupportedException。

        10
  •  1
  •   Peter    15 年前

    我总是提防编写自定义异常,纯粹是因为它们不总是被清晰地记录下来,如果命名不正确,就会引起混乱。

    在本例中,我将为标志检查失败抛出一个argumentexception。这完全取决于个人喜好。我看到的一些编码标准甚至定义了在这样的场景中应该抛出哪些类型的异常。

    如果用户试图传递一个不是枚举的东西,那么我将抛出一个InvalidOperationException。

    编辑:

    其他人提出了一个有趣的观点,即这是不支持的。对于NotSupportedException,我唯一关心的是,通常这些异常是在“暗物质”被引入系统时抛出的,或者换句话说,“这个方法必须进入这个接口上的系统,但在2.4版之前我们不会打开它。”

    我还看到NotSupportedExceptions作为一个许可例外被抛出,“您正在运行此软件的免费版本,不支持此功能”。

    编辑2:

    另一个可能的:

    System.ComponentModel.InvalidEnumArgumentException  
    

    使用作为枚举数的无效参数时引发的异常。

        11
  •  1
  •   TrueWill    15 年前

    我也会投票支持InvalidOperationException。我做了一个(不完整的)流程图 .NET exception throwing guidelines 基于 Framework Design Guidelines 2nd Ed. 如果有人感兴趣的话,请稍等。