开发者

Why does ConcurrentDictionary.TryRemove require a second out argument?

I only want to remove a value.. I don't need to use the variable afterwards. Why not include an overload where this second parameter was not required?

Do I really have to just store it in a temporary local variable, not use it, and have the garbage collector collect it when the method ends? Seems rather silly..

The function开发者_开发技巧: http://msdn.microsoft.com/en-us/library/dd287129.aspx


C#7 added discard syntactic sugar

So now you can write:

dictionary.TryRemove(entry.Key, out _); 

Reference

We allow "discards" as out parameters as well, in the form of a _, to let you ignore out parameters you don’t care about:

p.GetCoordinates(out var x, out _); // I only care about x


You can create exactly the method you want:

public static class ConcurrentDictionaryEx {
  public static bool TryRemove<TKey, TValue>(
    this ConcurrentDictionary<TKey, TValue> self, TKey key) {
    TValue ignored;
    return self.TryRemove(key, out ignored);
  }
}

UPDATE: Or, as Dialecticus mentioned in the comments, just use Remove. But note that, since it's an explicit interface implementation, you'll need a reference to an IDictionary<TKey, TValue>, which leads you back to creating an extension method if you want to avoid casting a ConcurrentDictionary<TKey, TValue> reference:

public static class ConcurrentDictionaryEx {
  public static bool Remove<TKey, TValue>(
    this ConcurrentDictionary<TKey, TValue> self, TKey key) {
      return ((IDictionary<TKey, TValue>)self).Remove(key);
  }
}


If you're not interested in the value that was removed, simply call IDictionary.Remove(key). It's shadowed, so you have to invoke it explicitly.

Example:

var dict = new ConcurrentDictionary<string, string>();
dict.AddOrUpdate("mykey", (val) => "test", (val1, val2) => "test");
((IDictionary)dict).Remove("mykey");

The TryRemove(key, out value) method is there to give you feedback whether the operation made any change. Use the one that best suits your needs.


I believe the 2nd argument is required is because you may need to do something with the item that you're removing from ConcurrentDictionary.

For example, imagine you have a ConcurrentDictionary<int, MyDisposable> where MyDisposable implements IDisposable. ConcurrentDictionary.TryRemove(...) doesn't call .Dispose(); on the item being removed from the dictionary.

In the code below, the .Dispose(); call succeeds because the MyDisposable hasn't been disposed, yet.

void Main()
{
    var dict = new ConcurrentDictionary<int, MyDisposable>();

    dict.TryAdd(1, new MyDisposable());

    dict.TryRemove(1, out var d);

    d.Dispose();
}

public class MyDisposable : IDisposable {

    #region IDisposable Support
    private bool disposedValue = false; // To detect redundant calls

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                // TODO: dispose managed state (managed objects).
            }

            // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
            // TODO: set large fields to null.

            disposedValue = true;
        }
    }

    // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
    // ~MyDisposable()
    // {
    //   // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
    //   Dispose(false);
    // }

    // This code added to correctly implement the disposable pattern.
    public void Dispose()
    {
        // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
        Dispose(true);
        // TODO: uncomment the following line if the finalizer is overridden above.
        // GC.SuppressFinalize(this);
    }
    #endregion

}


Now it has an overload that does not out any parameters:

public bool TryRemove(KeyValuePair<TKey, TValue> item)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜