Why does ConcurrentDictionary.TryRemove require a second out argument?

C#Dictionary

C# Problem Overview


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# Solutions


Solution 1 - C#

C#7 added discard syntactic sugar

So now you can write:

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

[Reference][1]

> 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

[1]: https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/ "Reference"

Solution 2 - C#

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

Solution 3 - C#

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.

Solution 4 - C#

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

}

Solution 5 - C#

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

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJohn SmithView Question on Stackoverflow
Solution 1 - C#robaudasView Answer on Stackoverflow
Solution 2 - C#JordãoView Answer on Stackoverflow
Solution 3 - C#andrew.foxView Answer on Stackoverflow
Solution 4 - C#Alex DreskoView Answer on Stackoverflow
Solution 5 - C#HamedView Answer on Stackoverflow