无效泛型类型参数的最佳例外

时间:2009-09-11 18:35:04

标签: c# generics exception

我目前正在为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课吗?使用InvalidOperationExceptionNotSupportedException?还有什么吗?

而不是没有为此创建我自己的例外,除非它显然是正确的。

11 个答案:

答案 0 :(得分:42)

NotSupportedException 听起来像明显适合,但文档明确指出它应该用于不同的目的。从MSDN类备注:

  

有些方法没有   支持在基类中,用   期望这些方法将是   在派生类中实现   代替。派生类可能   只实现方法的一个子集   从基类开始,抛出   NotSupportedException for   不支持的方法。

当然,有一种方式NotSupportedException显然足够好,特别是考虑到它的常识意义。话虽如此,我不确定它是否恰到好处。

鉴于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?

接受的答案所提出的问题

答案 1 :(得分:23)

我会避免使用NotSupportedException。此异常用于未实现方法的框架中,并且存在指示不支持此类操作的属性。它不适合这里

我认为InvalidOperationException是你可以抛出的最合适的异常。

答案 2 :(得分:12)

通用编程不应该在运行时抛出无效的类型参数。它不应该编译,你应该有一个编译时执行。我不知道IsFlag<T>()包含什么,但也许您可以将其转换为编译时执行,例如尝试创建只能使用'flags'创建的类型。也许traits课可以提供帮助。

<强>更新

如果你必须投掷,我会投票给InvalidOperationException。原因是泛型类型具有参数,与(方法)参数相关的错误以ArgumentException层次结构为中心。但是,ArgumentException上的recommendation声明了

  

如果失败不涉及   那么论证自己   应该是InvalidOperationException   使用

至少有一个信念的飞跃,方法参数建议也适用于泛型参数,但是没有更好的SystemException hierachy imho。

答案 3 :(得分:9)

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

答案 4 :(得分:8)

我会选择NotSupportedException。虽然ArgumentException看起来很好,但是当传递给方法的参数是不可接受的时,它确实是预期的。类型参数是您要调用的实际方法的定义特征,而不是真正的“参数”。如果您执行的操作在某些情况下有效,则应抛出InvalidOperationException,但对于特定情况,这是不可接受的。

当操作本身不受支持时,抛出

NotSupportedException。例如,在实现某个特定成员对某个类没有意义的接口时。这看起来像是类似的情况。

答案 5 :(得分:4)

显然,Microsoft会使用ArgumentException,例如“例外”部分中Expression.Lambda<>Enum.TryParse<>Marshal.GetDelegateForFunctionPointer<>的示例。我找不到任何其他示例(尽管搜索TDelegateTEnum的本地参考来源。)

因此,我认为可以安全地假设至少在Microsoft代码中,除了基本变量之外,使用ArgumentException作为无效泛型类型参数是一种常见做法。鉴于docs中的异常描述不区分这些,它也不是太多。

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

答案 6 :(得分:3)

我与NotSupportedExpcetion一起使用。

答案 7 :(得分:2)

在任何可疑的情况下,应始终抛出自定义异常。无论API用户需要什么,自定义异常都将始终有效。如果他不关心,开发人员可以捕获任何异常类型,但如果开发人员需要特殊处理,他将是SOL。

答案 8 :(得分:1)

我总是对编写自定义异常持谨慎态度,纯粹是因为它们并不总是清楚地记录下来,如果没有正确命名会导致混淆。

在这种情况下,我会为标志检查失败抛出ArgumentException。这完全取决于偏好。我所看到的一些编码标准甚至可以定义在这样的场景中应该抛出哪些类型的异常。

如果用户试图传入一些不是enum的内容,那么我会抛出一个InvalidOperationException。

编辑:

其他人提出了一个有趣的观点,即不支持这一点。我对NotSupportedException的唯一顾虑是,通常那些是当“暗物质”被引入系统时被抛出的异常,或换句话说,“这个方法必须进入系统在这个界面,但我们赢了“打开它直到版本2.4”

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

编辑2:

另一个可能的:

System.ComponentModel.InvalidEnumArgumentException  

使用作为枚举数的无效参数时抛出的异常。

答案 9 :(得分:1)

如何从NotSupportedException继承。虽然我同意@Mehrdad认为它最有意义,但我听到你的观点,它似乎并不完美。所以从NotSupportedException继承,这样人们对你的API进行编码仍然可以捕获NotSupportedException。

答案 10 :(得分:1)

我也会投票给InvalidOperationException。如果有人感兴趣的话,我会根据.NET exception throwing guidelinesFramework Design Guidelines 2nd Ed.上做一个(不完整的)流程图。