我使用ConcurrentDictionary<TKey, TValue>来实现ConcurrentSet<T>

public class ConcurrentSet<T> : ISet<T>
{
    private readonly ConcurrentDictionary<T, byte> collection;
}


ConcurrentDictionary<TKey, TValue>不能包含带有空键的一对。

// summary, param, returns...
/// <exception cref="ArgumentNullException">
///     <paramref name="item" /> is null.
/// </exception>
public bool Add(T item)
{
    // This throws an argument null exception if item is null.
    return this.collection.TryAdd(item, 0);
}


所以,我应该

if (item == null)
    throw new ArgumentNullException("item", "Item must not be null.");

return this.collection.TryAdd(item, 0);


或者,我应该

try
{
    return this.collection.TryAdd(item, 0);
}
catch (ArgumentNullException)
{
    throw new ArgumentNullException("item", "Item must not be null.");
}


或者,我应该

try
{
    return this.collection.TryAdd(item, 0);
}
catch (ArgumentNullException x)
{
    // I know, but I don't want to preserve the stack trace
    // back to the underlying dictionary, anyway.
    throw x;
}


或者,我应该

try
{
    return this.collection.TryAdd(item, 0);
}
catch (ArgumentNullException)
{
    // The thrown exception will have "key", instead of
    // "item" as the parameter's name, in this instance.
    throw;
}


正确的方法是什么?

最佳答案

您应该做什么取决于您要记录的课堂活动。如果您希望证明添加空项目的尝试可能会以未指定的方式失败,则只需直接进行调用并让任何异常冒出来。如果您希望证明您将返回一个ArgumentNullExceptionParamName等于item并且不希望依赖ConcurrentDictionary收到空键时的行为,那么您应该在输入之前检查该参数。将其传递给ConcurrentDictionary。如果您希望证明您的代码将抛出ArgumentNullExceptionParamName等于item的代码,但愿意依靠ConcurrentDictionary验证其参数并抛出ArgumentException,并且性能至关重要,另一种可能性是:

try
{
    return this.collection.TryAdd(item, 0);
}
catch (ArgumentNullException ex)
{
    if (ex.ParamName == "key" && item == null)
        throw new ArgumentNullException("item", "Item must not be null.");
    else
        throw;
}


此代码避免了在参数不为null的情况下(参数应为99.9999%的情况下)的情况下进行参数验证的任何额外费用,但仍将确保它仅声明是ArgumentNullException的来源。由于预期原因发生此类异常的情况;如果ConcurrentDictionary中的错误导致它意外地向其内部调用的方法传递了null参数,即使给它添加了非null项,上述代码也将确保原始异常堆栈跟踪不会丢失。请注意,另一种可能是:

    if (ex.ParamName == "key" && item == null)
        throw new ArgumentNullException("item", "Item must not be null.");
    else
        throw new UnexpectedException(ex); // Probably a custom type


基本思想是,如果ArgumentNullException由于除ConcurrentDictionary.Add为null之外的其他原因而从item逃脱,则此类异常不应被可能期望您使用ArgumentNullException的代码捕获。

10-08 03:37