我应该抛出ArgumentException吗?

ror*_*.ap 1 .net c# msdn exception argumentexception

这个问题是关于约定和解释MSDN的,所以我不认为它主要是基于意见的.

我想知道ArgumentException:我有一个构建器类,用于构建一个过滤器对象,该过滤器对象将在从邮箱中检索一组电子邮件时应用.构建器有许多方法可以设置过滤器选项.例如,我有两种设置过滤器"发送日期"范围的方法 - 在XX之前发送和/或在XX之后发送.我想为每个添加一个保护条款,如果提供的"之前"日期提供的"之后"日期之后,则会抛出异常.我会用一个通用的验证方法来做到这一点:

/// <summary>
/// This class provides methods for validating dates in various ways.
/// </summary>
internal static class DateValidation
{
    /// <summary>
    /// Validate the provided "start" and "end" date/time values.
    /// If they do not represent a valid range, throw an exception.
    /// </summary>
    /// <param name="start">The date/time that represents the start of the range.</param>
    /// <param name="end">The date/time that represents the end of the range.</param>
    internal static void ValidateDateTimeRange(DateTime? start, DateTime? end)
    {
        if (start.HasValue && end.HasValue)
        {
            if (start.Value > end.Value) 
                throw new Exception(
                string.Format(@"The start date/time ""{0}"" " +
                @"occurs after the end date/time ""{1}"".", 
                start.ToString(), end.ToString()));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是两种构建器方法:

/// <summary>
/// Set a value which represents a date/time after which
/// messages must have been sent to be part of filtered output.
/// </summary>
/// <param name="afterDateTime">The date/time after which
/// messages must have been sent to be part of filtered output.</param>
public void SetSentAfterDateTime(DateTime afterDateTime)
{
    DateValidation.ValidateDateTimeRange(afterDateTime, _sentBeforeDateTime);
    _sentAfterDateTime = afterDateTime;
}

/// <summary>
/// Set a value which represents a date/time before which
/// messages must have been sent to be part of filtered output.
/// </summary>
/// <param name="beforeDateTime">The date/time before which
/// messages must have been sent to be part of filtered output.</param>    
public void SetSentBeforeDateTime(DateTime beforeDateTime)
{
    DateValidation.ValidateDateTimeRange(_sentAfterDateTime, beforeDateTime);
    _sentBeforeDateTime = beforeDateTime;
}
Run Code Online (Sandbox Code Playgroud)

根据MSDN:

最常见的是,公共语言运行库或其他类库抛出ArgumentException并指示开发人员错误.

我知道"最常见"这个短语为我的其他用法留下了可能性,但我喜欢坚持惯例.我正在构建一个公共API,因此异常将被记录下来,并将超出公共接口; 此外,它不"表示开发人员错误".可以想象它可以指示用户错误(使用异常来处理用户输入验证问题是一种常见的惯例).不过,基于MSDN描述,我觉得这不是它的目的.

...应该使用派生类[ArgumentNullException和ArgumentOutOfRangeException]代替ArgumentException,除非在两个派生类都不可接受的情况下.例如,应该抛出异常:

...

当参数的值超出可接受值的范围时,ArgumentOutOfRangeException; 例如,在创建DateTime期间将值"46"作为month参数传递.

我的参数可能超出了可接受值的范围,但该条件是根据其他日期/时间值动态确定的.没有静态范围的值超出范围.

那么ArgumentException通常用于这样的情况?

Eri*_*ert 10

我同意接受的答案; 我想补充一点,如果你的代码将你的调用者放在必须捕获异常的位置以确定用户提供的数据是否有效,那么你已经做了我称之为"烦恼的异常".令人烦恼的是,您必须创建一个异常处理程序来处理非异常情况.输入不一致日期范围的用户也不例外.这是该计划工作流程的正常部分.

考虑在用户界面层中解决问题.实施日期选择器,以便它们不允许用户选择会产生异常的日期组合.有很多方法可以做到这一点 - 例如,灰色日期是无效的.或者检测不一致性并使拾取器变为红色或闪光或其他任何东西,并防止操作被提交.


Kri*_*ten 7

如何设计 Krzysztof Cwalina的异常层次结构:

通过更改调用例程的代码可以避免使用错误.

我们同意这是一个使用错误.

Eric Lippert称他们为Boneheaded例外:

Boneheaded异常是你自己的错误,你可以防止它们,因此它们是你的代码中的错误.你不应该抓住它们; 这样做会隐藏代码中的错误.

开发人员不应该使用catch这些类型的错误,而是更改调用代码以确保首先不会发生异常.这就是为什么确切的异常类型并不重要.

正如Cwalina所说:

需要将使用错误传达给调用例程的人类开发人员.异常类型不是向人类传达错误的最佳方式.消息字符串是一种更好的方法.因此,对于因使用错误而抛出的异常,我将专注于设计一个非常好的(即解释性)异常消息并使用现有的.NET Framework异常类型之一:ArgumentNullException,ArgumentException,InvalidOperationException,NotSupportedException等换句话说,不要为使用错误创建新的异常类型,因为异常的类型与使用错误无关..NET Framework已经有足够的类型(实际上太多,恕我直言)来表示我能想到的每个使用错误.

(强调我的)

无论你是使用ArgumentException还是使用,都无关紧要InvalidOperationException.选择一个,但要确保它有一个明确的Message.

  • @KrisVandermotten:这样看.要问的问题是"会改变参数的值来防止异常吗?" 写入封闭管道时,没有参数可用,因此它不应该是参数异常.但是传递错误的日期可以通过传递正确的日期来修复,因此它是一个参数例外.实现这一区别的目的是让错误调用者的开发人员更容易找到他们的错误. (2认同)