3

ConcurrentDictionary<TKey, TValue>を実装するために使用しますConcurrentSet<T>

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

ConcurrentDictionary<TKey, TValue>null キーとのペアを含めることはできません。

// 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;
}

これを行う適切な方法は何ですか?

4

4 に答える 4

7

私はこれのどちらかで行きます

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);

null があるかどうかは、クラスが気にするかどうかによって異なります。

null チェックを実行する唯一の理由が null を に渡さTryAddないようにすることである場合は、わざわざチェックしないでください。 TryAdd独自のチェックを行い、例外をスローします。

ある時点で、null を許可する別のコレクションを使用する可能性があると思われるが、コレクションに null を持たせたくない場合は、自分で確認する必要があります。これにより、将来の時点で変更が発生した場合に保護されます。

パラメータの検証は、常にメソッドが最初に実行する必要があります。パラメータが無効な場合は、他に何をしても意味がありません。

例外で何かを行う場合にのみ、例外をキャッチする必要があります。再スローするか、同等の新しい式を作成するだけの場合は、わざわざキャッチしないでください。

于 2013-04-17T16:36:10.597 に答える
1

何をすべきかは、クラスが何をしていると文書化したいかによって異なります。null アイテムを追加しようとすると不特定の方法で失敗する可能性があることを文書化したい場合は、単純に直接呼び出しを行い、例外が発生するのを待ちます。ArgumentNullExceptionParamName等しい を返すことをドキュメント化し、null キーを受け取ったときitemの動作に依存したくないConcurrentDictionary場合は、 に渡す前に引数を確認する必要がありますConcurrentDictionaryArgumentNullExceptionコードがParamNameequal toをスローすることを文書化したいが、その引数を検証して をスローするためにitemに依存しても構わないと思っていて、パフォーマンスが重要である場合、別の可能性は次のようになります。ConcurrentDictionaryArgumentException

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

基本的な考え方は、null以外の何らかの理由でanArgumentNullExceptionがエスケープされた場合、そのような例外は、あなたからの an を期待する可能性のあるコードによってキャッチされるべきではないということです。ConcurrentDictionary.AdditemArgumentNullException

于 2013-04-18T15:52:05.967 に答える
0

あなたの例では、それらはすべてあまりにも似ていますが、最初のオプションを使用します。

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

を必要とせず、catchよりコンパクトに見えるためです。また、要件が変更され、次のようなコード行が追加されない場合に、条件を拡張することもできます。

if (item==null || item.Name == null)
    throw...
于 2013-04-17T16:35:43.983 に答える