我使用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;
}
正确的方法是什么?
最佳答案
您应该做什么取决于您要记录的课堂活动。如果您希望证明添加空项目的尝试可能会以未指定的方式失败,则只需直接进行调用并让任何异常冒出来。如果您希望证明您将返回一个ArgumentNullException
且ParamName
等于item
并且不希望依赖ConcurrentDictionary
收到空键时的行为,那么您应该在输入之前检查该参数。将其传递给ConcurrentDictionary
。如果您希望证明您的代码将抛出ArgumentNullException
且ParamName
等于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
的代码捕获。