ConcurrentDictionary AddOrUpdateの更新部分に追加するもの


109

辞書を使用してコードを書き直してConcurrentDictionaryを使用しようとしています。いくつかの例を確認しましたが、まだAddOrUpdate関数の実装に問題があります。これは元のコードです:

    dynamic a = HttpContext;
    Dictionary<int, string> userDic = this.HttpContext.Application["UserSessionList"] as Dictionary<int, String>;

   if (userDic != null)
   {
      if (useDic.ContainsKey(authUser.UserId))
      {
        userDic.Remove(authUser.UserId);
      }
   }
  else
  {
     userDic = new Dictionary<int,string>();
  }
  userDic.Add(authUser.UserId, a.Session.SessionID.ToString());
  this.HttpContext.Application["UserDic"] = userDic;

更新部分に何を追加するのかわかりません:

userDic.AddOrUpdate(authUser.UserId,
                    a.Session.SessionID.ToString(),
                    /*** what to add here? ***/);

どんなポインタでもいただければ幸いです。

回答:


220

Func更新の場合にディクショナリに格納される値を返すを渡す必要があります。あなたの場合(追加と更新を区別しないので)これは次のようになると思います:

var sessionId = a.Session.SessionID.ToString();
userDic.AddOrUpdate(
  authUser.UserId,
  sessionId,
  (key, oldValue) => sessionId);

Funcつまり、は常にsessionIdを返すため、追加と更新の両方が同じ値を設定します。

ところで、MSDNページにサンプルがあります


4
同じ値に追加または更新する関数を見つけるために真剣に戦いました。thaks
Zapnologica

2
いい答えだ。Visual Studioに表示されるAddOrUpdate()のシグニチャーから、2つのパラメーターの意味のみを推測できます。しかし、@ user438331が尋ねる特定のケースでは、単純なインデクサーを使用した私の答えの解決策の方が良いと思います。
Niklas Peter

7
@NiklasPeterが指摘しているように(stackoverflow.com/a/32796165/8479)、通常のインデクサーを使用して値を上書きする方がよいでしょう。なぜなら、あなたの場合、既存の値があっても興味がないからです。はるかに読みやすいです。
Rory

3
@NiklasPeterの回答をユーザーに示すように、回答を変更することをお勧めします。それははるかに優れたソリューションです。
ウィルカルダーウッド2017

63

私はあなたの質問で何も見逃さなかったことを願っていますが、なぜこれだけではないのですか?より簡単で、アトミックで、スレッドセーフです(以下を参照)。

userDic[authUser.UserId] = sessionId;

キーと値のペアを無条件にディクショナリに格納し、キーがすでに存在する場合はそのキーの値を上書きします。インデクサーのセッターを使用します

(参照:http : //blogs.msdn.com/b/pfxteam/archive/2010/01/08/9945809.aspx

インデクサーもアトミックです。代わりに関数を渡した場合、そうでない可能性があります。

これらの操作はすべてアトミックであり、ConcurrentDictionaryでの他のすべての操作に関してスレッドセーフです。各操作のアトミック性に対する唯一の警告は、デリゲートを受け入れる操作、つまりAddOrUpdateとGetOrAddに関するものです。[...]これらのデリゲートはロックの外で呼び出されます

参照:http : //blogs.msdn.com/b/pfxteam/archive/2010/01/08/9945809.aspx


2
はい、不可分です。一度にすべてが発生し、半分が発生したり中断されたりすることはありません。ただし、実行する直前に他の誰かが別の値に変更できるという点で安全ではありません。その場合、変更は失われ、変更が発生したことはわかりません。値が期待どおりの場合にのみ変更したい場合これはあなたのためにそれをしません。
トランプスター

26

私は拡張メソッドを実装することになりました:

static class ExtensionMethods
{
    // Either Add or overwrite
    public static void AddOrUpdate<K, V>(this ConcurrentDictionary<K, V> dictionary, K key, V value)
    {
        dictionary.AddOrUpdate(key, value, (oldkey, oldvalue) => value);
    }
}

1

興味がある人のために、私は現在、新しい値を強制する代わりに「oldValue」または既存の値を使用するための優れた例であるケースを実装しています(個人的には「oldValue」という用語は好きではないので、パラレルスレッド内から数プロセッサティック前に作成されたときの古いバージョン)。

dictionaryCacheQueues.AddOrUpdate(
    uid,
    new ConcurrentQueue<T>(),
    (existingUid, existingValue) => existingValue
);

6
既存の値を変更したくない場合は、GetOrAdd()代わりにmsdn.microsoft.com/en-us/library/ee378674(v=vs.110).aspx
Rory

1
ええ、そうです、この場合、GetOrAdd()の方が単純で十分です。このヒントにはthxを使用します。
Nicolas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.