Many times over the years, I have needed code that does:
Find a value in a dictionary; if it is not there, add it to the dictionary (and return that new value).
For example:
// Only one per account, so loading can be efficiently managed.
// <AccountID, LCProfilePicture>
public readonly static Dictionary<int, LCProfilePicture> All = new Dictionary<int, LCProfilePicture>();
public static LCProfilePicture GetOrCreate( int accountID )
{
LCProfilePicture pic;
if (!All.TryGetValue( accountID, out pic )) {
pic = new LCProfilePicture( accountID );
All[ accountID ] = pic;
}
return pic;
}
Instead of having to write that boilerplate each time, I'd like to have a generic method that will do the work. How to do so in c#?
So far, I have thought of three ways to proceed:
Wrap the construction that will be needed if the dictionary does not already contain an object for the key, into an Action (or Func?). Then call that if necessary.
Require TValue to have a constructor of that form, and then somehow describe that requirement as a constraint on the generic method.
Define some interface that TValue has to satisfy, and somehow use that interface to write the generic method.
I think I know how to do #1, so will submit an answer doing so, as soon as I work out the details. UPDATE: I have now worked that out, and posted that as an answer.
But maybe #2 is possible? Then I could just add that constraint, and be done.
Pro: easier to use (don't have to wrap the construction into an Action or Func).
Con: Not as flexible (if have a TValue that does not have such a constructor, can't use this generic method).
(#3 seems less promising; I mention it for completeness.)
You can combine constraints of new() and an interface for setting the key, like this:
interface IWithKey<T> {
public T Key { get; set; }
}
static class DictExtensions {
public static TVal GetorCreate<TKey,TVal>(this IDictionary<TKey,TVal> d, TKey key) where TVal : new(), IWithKey<TKey> {
TVal res;
if (!d.TryGetValue(key, out res)) {
res = new TVal();
res.Key = key;
d.Add(key, res);
}
return res;
}
}
Since GetorCreate is an extension, you can use it as follows:
static LCProfilePicture GetOrCreatePic( int accountID ) {
return All.GetOrCreateEntry(accountID);
}
I noticed in your example you have a static dictionary
// Only one per account, so loading can be efficiently managed.
// <AccountID, LCProfilePicture>
public readonly static Dictionary<int, LCProfilePicture> All =
new Dictionary<int, LCProfilePicture>();
My first reaction to that is, since it is static, are you going to need it to be thread safe. If the answer is yes, maybe, or even no, then the answer might be, don't write it yourself, let Microsoft do it.
System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>
Which so happens to have 2 built in functions
TValue GetOrAdd(TKey key, TValue value)
TValue GetOrAdd(TKey key, Func<TKey, TValue> func)
And all of that done in a thread-safe manner.
The second one where the parameter is a Func is the maybe the answer you are looking for.
If you are set on simplifying the usage, I would argue against having the loading of the data be part of the TValue. That is mostly based on my own person preference to store POCO (Plain Old CLR Objects) as values is Dictionaries and not objects with State and Behavior.
I would instead, move the "loading/constructing/deserializing" behavior to another service and/or the Dictionary itself.
This example creates a base class that you inherit from
public abstract class SmartConcurrentDictionaryBase<TKey, TValue> :
System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>
{
public TValue GetOrAdd(TKey key) { return GetOrAdd(key, LoadNewValue); }
protected abstract TValue LoadNewValue(TKey key);
}
public class LCProfilePictureDictionary : SmartConcurrentDictionaryBase<int, LCProfilePicture>
{
protected override LCProfilePicture(int accountID)
{
return new LCProfilePicture(accountID);
}
}
// use is
// var pic = All.GetOrAdd(accountID);
This example is more of a reusable Dictionary object and takes in a Func as a constructor parameter, but could easily be changed to include an Interface where one of the functions on the interface match the pattern.
public class SimpleConcurrentDictionary<TKey, TValue> :
System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>
{
private readonly Func<TKey, TValue> _loadFunc;
public SimpleConcurrentDictionary(Func<TKey, TValue> loadFunc)
{
_loadFunc = loadFunc;
}
public TValue GetOrAdd(TKey key) { return GetOrAdd(key, _loadFunc); }
}
System.Reflection has a ConstructorInfo object and a GetConstructor method that can be used for this purpose. ConstructorInfo.Invoke returns an object of the type that you used to create your ConstructorInfo. If you went the reflection route, it would look something like this (not tested, but should be close):
//using System.Reflection;
public static TValue GetOrCreateEntry<TKey, TValue>(Dictionary<TKey, TValue> dict, TKey key)
{
TValue value;
if (!dict.TryGetValue(key, out value))
{
// not in dictionary
ConstructorInfo ctor = typeof(TValue).GetConstructor(new Type[] { typeof(TKey) });
if (ctor != null)
{
// we have a constructor that matches the type you need
value = (TValue)ctor.Invoke(new object[] { key });
dict[key] = value;
return value;
}
else
throw new NotImplementedException(); // because the TValue type does not implement the constructor you anticipate
}
// we got it from dictionary, so just return it
return value;
}
Solution #1 (most general):
public static TValue GetOrCreateEntry<TKey, TValue>( Dictionary<TKey, TValue> dict, TKey key, Func<TValue> creator )
{
TValue value;
if (!dict.TryGetValue( key, out value )) {
value = creator();
dict[ key ] = value;
}
return value;
}
Example usage:
static LCProfilePicture GetOrCreatePic( int accountID )
{
return GetOrCreateEntry<int, LCProfilePicture>( All, accountID, () => new LCProfilePicture( accountID ) );
}
Solution #2 (for TValues that remember their key):
public static TValue GetOrCreateEntry<TKey, TValue>( Dictionary<TKey, TValue> dict, TKey key, Func<TKey, TValue> creator )
{
TValue value;
if (!dict.TryGetValue( key, out value )) {
value = creator(key);
dict[ key ] = value;
}
return value;
}
Example usage:
static LCProfilePicture GetOrCreatePic( int accountID )
{
return GetOrCreateEntry<int, LCProfilePicture>( All, accountID, key => new LCProfilePicture( key ) );
}
Comparison of Solution #1 and Solution 2:
Solution #1 is more general - it can be used even for TValues that don't need to know about the key.
Solution #2 is cleaner style, for TValues that do retain a reference to the key.
Two reasons #2 is preferable, where appropriate:
Reason #1: Solution #1 has the possibility of abuse: consider the case where TValue has two constructors, a parameterless one, and one that takes key as a parameter. An inexperienced programmer might use Solution #1 like this:
static LCProfilePicture GetOrCreatePic( int accountID )
{
// OOPS, programmer has not set the key field to "accountID".
return GetOrCreateEntry<int, LCProfilePicture>( All, accountID, () => new LCProfilePicture() );
}
If the lead programmer / architect wants to avoid that possibility, omit Solution #1, and only offer #2. In that case, the attempted usage won't compile, because there is no matching constructor.
Reason #2: Using Solution #1 requires including a second copy of the key in the usage, if TValue needs to capture it. This unnecessarily encapsulates the key in the Func instance, and could lead to accidentally referring to a different key, e.g.:
//...
int keyA;
int keyB;
// OOPS, programmer referred to the wrong key the second time.
// Maybe copy/pasted code, and only changed it in the first location, not realizing it is used in two places.
var valA = GetOrCreateEntry<int, LCProfilePicture>( All, keyA, () => new LCProfilePicture( keyB) );
enter code here
Related
This question already has answers here:
Is there an IDictionary implementation that, on missing key, returns the default value instead of throwing?
(17 answers)
Closed 5 years ago.
In some certain scenario it appeared to be useful for me to have a short-spoken, readable way to get null instead of the KeyNotFoundException while accessing dictionary value by key, when there is no such key in the dictionary.
The first thing that came into my mind was an extension method:
public static U GetValueByKeyOrNull<T, U>(this Dictionary<T, U> dict, T key)
where U : class //it's acceptable for me to have this constraint
{
if (dict.ContainsKey(key))
return dict[key];
else
//it could be default(U) to use without U class constraint
//however, I didn't need this.
return null;
}
But it's not very short-spoken actually, when you write something like this:
string.Format("{0}:{1};{2}:{3}",
dict.GetValueByKeyOrNull("key1"),
dict.GetValueByKeyOrNull("key2"),
dict.GetValueByKeyOrNull("key3"),
dict.GetValueByKeyOrNull("key4"));
I'd say, it would be much better to havesomething close to base syntax: dict["key4"].
Then I came up with an idea to have a class with a private dictionary field, which exposed the functionality I need:
public class MyDictionary<T, U> //here I may add any of interfaces, implemented
//by dictionary itself to get an opportunity to,
//say, use foreach, etc. and implement them
// using the dictionary field.
where U : class
{
private Dictionary<T, U> dict;
public MyDictionary()
{
dict = new Dictionary<T, U>();
}
public U this[T key]
{
get
{
if (dict.ContainsKey(key))
return dict[key];
else
return null;
}
set
{
dict[key] = value;
}
}
}
But it seems a little overhead to get the slight change in the basic behaviour.
One more workaround could be to define a Func in the current context like this:
Func<string, string> GetDictValueByKeyOrNull = (key) =>
{
if (dict.ContainsKey(key))
return dict[key];
else
return null;
};
so it could be utilized like GetDictValueByKeyOrNull("key1").
Could you, please, give me any more suggestions or help to choose a better one?
Here is my solution from my personal library, implemented as an extension method. I am only posting it because it is implemented from the dictionary interface and allows an optional default value to be passed in.
Implementation
public static TV GetValue<TK, TV>(this IDictionary<TK, TV> dict, TK key, TV defaultValue = default(TV))
{
TV value;
return dict.TryGetValue(key, out value) ? value : defaultValue;
}
Usage
MyDictionary.GetValue("key1");
MyDictionary.GetValue("key2", -1);
MyDictionary.GetValue("key3")?.SomeMethod();
You can't get the syntax you want with an extension method, and as others have said overriding a method/operator to change its behavior is generally not a great idea. I think the best you can do is shorten the name you use.
That's if you need to keep to the IDictionary interface. If you aren't interfacing with any code that expects an IDictionary, then you are free to define your own interface and having the [] operator work differently isn't a problem.
Whatever you end up calling the function, you'll want to implement it like this:
public static U Get<T, U>(this Dictionary<T, U> dict, T key)
where U : class
{
U val;
dict.TryGetValue(key, out val);
return val;
}
It just does one lookup, compared with 2 for your implementations.
In the end I came up with a variant using a deriving from dictionary class with explicit interface implementation:
public interface INullValueDictionary<T, U>
where U : class
{
U this[T key] { get; }
}
public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
where U : class
{
U INullValueDictionary<T, U>.this[T key]
{
get
{
U val;
this.TryGetValue(key, out val);
return val;
}
}
}
So it exposes the functionality I need the following way:
//create some dictionary
NullValueDictionary<int, string> dict = new NullValueDictionary<int, string>
{
{1,"one"}
};
//have a reference to the interface
INullValueDictionary<int, string> idict = dict;
try
{
//this throws an exception, as the base class implementation is utilized
Console.WriteLine(dict[2] ?? "null");
}
catch { }
//this prints null, as the explicit interface implementation
//in the derived class is used
Console.WriteLine(idict[2] ?? "null");
Add a DictionaryExtension class
public static class DictionaryExtension
{
public static TValue GetValueOrDefault<TKey, TValue>
( this IDictionary<TKey, TValue> dictionary,TKey key)
{
TValue value;
return dictionary.TryGetValue(key, out value) ? value : default(TValue);
}
}
And it can return Default value if not found key in dictionary.
The Default is null if this is reference type .
_dic.GetValueOrDefault();
Worth pointing out that the HybridDictionary does this by default.
You lose the generic typeing, but get the null-if-not-found functionality.
And (at least theoretically) you get performance benefits at low numbers of values, I think.
I premise by saying that I would not use this. The new keyword, while useful in this case, can create bugs which are really hard to find. Other than that, you can try this class.
class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
public new TValue this[TKey key]
{
get
{
TValue value;
return TryGetValue(key, out value) ? value : default(TValue);
}
set { base[key] = value; }
}
}
I've done this before and it worked pretty well to just inherit the regular Dictionary class and just hide the indexer. It's really clean to do it this way so you automatically acquire all the reliability and familiarity of the Regular Dictionary class.
public class NullSafeDict<TKey, TValue> : Dictionary<TKey, TValue> where TValue : class
{
public new TValue this[TKey key]
{
get
{
if (!ContainsKey(key))
return null;
else
return base[key];
}
set
{
if (!ContainsKey(key))
Add(key, value);
else
base[key] = value;
}
}
}
All I want is a dictionary which tells me which key it couldn't find, rather than just saying The given key was not present in the dictionary.
I briefly considered doing a subclass with override new this[TKey key], but felt it was a bit hacky, so I've gone with implementing the IDictionary interface, and passing everything through directly to an inner Dictionary, with the only additional logic being in the indexer:
public TValue this[TKey key]
{
get
{
ThrowIfKeyNotFound(key);
return _dic[key];
}
set
{
ThrowIfKeyNotFound(key);
_dic[key] = value;
}
}
private void ThrowIfKeyNotFound(TKey key)
{
if(!_dic.ContainsKey(key))
throw new ArgumentOutOfRangeException("Can't find key [" + key + "] in dictionary");
}
Is this the right/only way to go? Would newing over the this[] really be that bad?
Sounds like a good fit for an extension method:
public static class SomeUtilClass {
public static TValue VerboseGetValue<TKey, TValue>(
this IDictionary<TKey, TValue> data, TKey key)
{
TValue result;
if (!data.TryGetValue(key, out result)) {
throw new KeyNotFoundException(
"Key not found: " + Convert.ToString(key));
}
return result;
}
}
This will then work on all your existing dictionaries whenever you call VerboseGetValue, for example:
var data = new Dictionary<int, string> { { 123, "abc" } };
Console.WriteLine(data.VerboseGetValue(123));
Console.WriteLine(data.VerboseGetValue(456));
Instead of doing ContainsKey and checking for the presence of the key before touching the underlying dictionary, why not do
get {
try {
return _dic[key];
}
catch (ArgumentOutOfRangeException) {
throw new ArgumentOutOfRangeException(......);
}
}
That way, you only pay for the extra checking in the failure case - the success case, which is hopefully more common, doesn't have to do an extra dictionary lookup. This is good for get, but set is more difficult since the default behaviour of set is to always work. If you don't want that then you would need to check for the existence of the key first.
If you want to do this, you are going to have to roll your own in one way or another. But I'm going to question WHY you would want to do this?
Lot of times I have to create a Dictionary<KeyType, List<ValueType>>
Before I can start using the dictionary I have to first verify that List has been created for that key.
//Can i remove these two lines?
if(!dict.ContainsKey(key))
dict[key]= new List<ValueType>;
//now use the key
dict[key].Add(value);
I know its only "2 lines" of code but it annoys me and I think it can be removed.
I can extend dictionary in someway but before I do it, I want to know if someone has found a clever way to remove the above if statement.
Basically i want to create a Dictionary<KeyType, Collection<ValueType>> and start using it right away like dict[key].Add(value).
You could create something like Google Java Collection's Multimap... or you could just add an extension method like this:
public static void AddValue<TKey, TValue>
(this IDictionary<TKey, List<TValue>> dictionary, TKey key, TValue value)
{
List<TValue> values;
if (!dictionary.TryGetValue(key, out values))
{
values = new List<TValue>();
dictionary.Add(key, values);
}
values.Add(value);
}
As Bevan says, Lookup can help as well - but you can only create one with the ToLookup method, and you can't modify it afterwards. In many cases that's a thoroughly good thing, but if you need a mutable map then you'll ned something like the above.
Have a look at the LookUp class introduced with Linq in .NET 3.5 - it might be just what you're looking for: a Dictionary like class that supports multiple items per key.
Perhaps the only significant downside is that you have to have all your elements available in one batch, as LookUp is immutable.
The ConcurrentDictionary<T,K>.GetOrAdd method is amazingly useful.
private ConcurrentDictionary<string, ICollection<int>> _dictionary;
private static ICollection<int> CreateEmptyList(string dummyKey)
{
return new List<int>();
}
private void AddValue(string key, int value)
{
ICollection<int> values = _dictionary.GetOrAdd(key, CreateEmptyList);
values.Add(value);
}
Edit: Here's an example of how to implement the feature as an extension method for IDictionary<T,K> (C# 3):
Note that IDictionary<TKey, TValue> is generally not thread safe, so if you want thread safety with this extension method you'll have to manually implement it just as for other operations.
public static TValue GetOrAdd<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary,
TKey key,
Func<TKey, TValue> valueFactory)
{
TValue value;
if (!dictionary.TryGetValue(key, out value))
{
value = valueFactory(key);
dictionary.Add(key, value);
}
return value;
}
To add to the answers, you can also add a more general extension which accepts a delegate for instantiation:
public static TValue GetOrCreate<TKey, TValue>
(this IDictionary<TKey, TValue> dict,
TKey key,
Func<TKey, TValue> getValue)
{
TValue value;
if (!dict.TryGetValue(key, out value))
{
dict.Add(key, getValue(key));
}
return value;
}
and then you can provide whatever instantiation method you like:
Dictionary<int, string> dict = new Dictionary<int, string>();
string result = dict.GetOrCreate(5, i => i.ToString());
Basically, I want something like this:
Dictionary<object, string> dict = new Dictionary<object, string>();
dict.Add(null, "Nothing");
dict.Add(1, "One");
Are there any built into the base class library that allow this? The preceding code will throw an exception at runtime when adding the null key.
You could avoid using null and create a special singleton value class that does the same thing. For example:
public sealed class Nothing
{
public static readonly Nothing Value = new Nothing();
private Nothing() {}
}
Dictionary<object, string> dict = new Dictionary<object, string>();
dict.add(Nothing.Value, "Nothing");
dict.add(1, "One");
This approach will fail to work if you intend to make your collection more strongly typed - let's say for example you want the key to be a string. Since string is sealed you can't inherit from it to create a "special value" substitute for null. Your alternatives become a bit more complicated. You could:
Create some special constant value to represent the "empty" / "null" case. Kind of hacky and definitely a path to confusion. This can be a viable approach if the dictionary is completely private to some implementation class and you can write some Encode/Decode utility methods to avoid spreading the knowledge of how you translate keys all over the place.
Create your own implementation of IDictionary that internally delegates to a Dictionary<> instance - except for the case of null. This violates the documented expectations for the IDictionary<> interface which does say that null keys should throw an exception. But you may be able to get away with it if it's the only way to solve your real problem. This only works if you own and create the dictionary instance.
Find a way to solve your problem without storing a "null" key in the dictionary. For example, consider not populating the null key in the dictionary and having some special case logic to deal with it. Keys have to be hashable and comparable to work with the underlying implementation, which is why null is prohibited normally.
As an aside, does your dictionary key really need the key to be object? This can lead to subtle bugs due to reference equality being used where you may have intended Equals() to be evaluated as the basis for comparison.
How about this?
public class NullableDictionnary<T1, T2> : Dictionary<T1, T2>
{
T2 null_value;
public T2 this[T1 key]
{
get
{
if (key == null)
{ return null_value; }
return base[key];
}
set
{
if (key == null)
{ null_value = value; }
else
{ base[key] = value; }
}
}
}
NameValueCollection can take a null key but it does not implement IDictionary. It would however be pretty easy to derive from DictionaryBase and provide Add/Remove/Indexers etc that simply replace null with something built in like:
class MyDictionary : DictionaryBase {
private readonly object nullKey = new object();
void Add(object key, string value) {
if ( key == null ) { key = nullKey; }
.. call base methods
}
}
You can simply use ValueTuple as a wrapper for key, for example:
Dictionary<ValueTuple<string?>, string>
No need for a different implementation of Dictionary.
Take a look at my answer here:
https://stackoverflow.com/a/22261282/212272
You will also be able to keep your dictionary strongly typed:
var dict = new Dictionary<NullObject<int?>, string>();
dict[1] = "one int";
dict[null] = "null int";
Assert.AreEqual("one int", dict[1]);
Assert.AreEqual("null int", dict[null]);
If key is enum, you can use not existing value instead of null like (YourEnum)(-1)
Does the key literally need to be NULL? The key in the collection works out to be an index. It doesn't make a lot of sense to me to have NULL for an index in a collection.
Maybe create a new class
public class ObjectEntry
{
public object objRef;
public string desc;
public ObjectEntry(object objectReference)
{
objRef = objectReference;
if (objRef = null) {desc = "Nothing";}
else {desc = objRef.Description;} //or whatever info you can get from a proper objRef value
}
}
newObj = new ObjectEntry(null);
dict.add(newObj, newObj.desc);
A slight variation on jestro's answer to make for a cleaner(to me) solution that makes it more explicit what you are trying to do. Obviously this could be extended as needed. But you get the picture, just make a wrapper.
public class NullDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
private TValue _default;
public new TValue this[TKey key]
{
get {
if(key == null)
{
return _default;
}
return _decorated[key];
}
}
private Dictionary<TKey, TValue> _decorated;
public NullDictionary( Dictionary<TKey,TValue> decorate, TValue defaultValue = default)
{
_decorated = decorate;
_default = defaultValue;
}
}
The indexer into Dictionary throws an exception if the key is missing. Is there an implementation of IDictionary that instead will return default(T)?
I know about the TryGetValue() method, but that's impossible to use with LINQ.
Would this efficiently do what I need?:
myDict.FirstOrDefault(a => a.Key == someKeyKalue);
I don't think it will as I think it will iterate the keys instead of using a Hash lookup.
Indeed, that won't be efficient at all.
As per comments, in .Net Core 2+ / NetStandard 2.1+ / Net 5, MS added the extension method GetValueOrDefault()
For earlier versions you can write the extension method yourself:
public static TValue GetValueOrDefault<TKey,TValue>
(this IDictionary<TKey, TValue> dictionary, TKey key)
{
TValue ret;
// Ignore return value
dictionary.TryGetValue(key, out ret);
return ret;
}
Or with C# 7.1:
public static TValue GetValueOrDefault<TKey,TValue>
(this IDictionary<TKey, TValue> dictionary, TKey key) =>
dictionary.TryGetValue(key, out var ret) ? ret : default;
That uses:
An expression-bodied method (C# 6)
An out variable (C# 7.0)
A default literal (C# 7.1)
If you're using .NET Core 2 or above (C# 7.x), the CollectionExtensions class is introduced and you can use the GetValueOrDefault method to get default value if key is not there in a dictionary.
Dictionary<string, string> colorData = new Dictionary<string, string>();
string color = colorData.GetValueOrDefault("colorId", string.Empty);
Carrying these extension methods can help..
public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dict, K key)
{
return dict.GetValueOrDefault(key, default(V));
}
public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dict, K key, V defVal)
{
return dict.GetValueOrDefault(key, () => defVal);
}
public static V GetValueOrDefault<K, V>(this IDictionary<K, V> dict, K key, Func<V> defValSelector)
{
V value;
return dict.TryGetValue(key, out value) ? value : defValSelector();
}
Collections.Specialized.StringDictionary provides a non-exception result when looking up a missing key's value. It is also case-insensitive by default.
Caveats
It is only valid for its specialized uses, and — being designed before generics — it doesn't have a very good enumerator if you need to review the whole collection.
If you're using .Net Core, you can use the CollectionExtensions.GetValueOrDefault method. This is the same as the implementation provided in the accepted answer.
public static TValue GetValueOrDefault<TKey,TValue> (
this System.Collections.Generic.IReadOnlyDictionary<TKey,TValue> dictionary,
TKey key);
public class DefaultIndexerDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private IDictionary<TKey, TValue> _dict = new Dictionary<TKey, TValue>();
public TValue this[TKey key]
{
get
{
TValue val;
if (!TryGetValue(key, out val))
return default(TValue);
return val;
}
set { _dict[key] = value; }
}
public ICollection<TKey> Keys => _dict.Keys;
public ICollection<TValue> Values => _dict.Values;
public int Count => _dict.Count;
public bool IsReadOnly => _dict.IsReadOnly;
public void Add(TKey key, TValue value)
{
_dict.Add(key, value);
}
public void Add(KeyValuePair<TKey, TValue> item)
{
_dict.Add(item);
}
public void Clear()
{
_dict.Clear();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return _dict.Contains(item);
}
public bool ContainsKey(TKey key)
{
return _dict.ContainsKey(key);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
_dict.CopyTo(array, arrayIndex);
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _dict.GetEnumerator();
}
public bool Remove(TKey key)
{
return _dict.Remove(key);
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
return _dict.Remove(item);
}
public bool TryGetValue(TKey key, out TValue value)
{
return _dict.TryGetValue(key, out value);
}
IEnumerator IEnumerable.GetEnumerator()
{
return _dict.GetEnumerator();
}
}
One could define an interface for the key-lookup function of a dictionary. I'd probably define it as something like:
Interface IKeyLookup(Of Out TValue)
Function Contains(Key As Object)
Function GetValueIfExists(Key As Object) As TValue
Function GetValueIfExists(Key As Object, ByRef Succeeded As Boolean) As TValue
End Interface
Interface IKeyLookup(Of In TKey, Out TValue)
Inherits IKeyLookup(Of Out TValue)
Function Contains(Key As TKey)
Function GetValue(Key As TKey) As TValue
Function GetValueIfExists(Key As TKey) As TValue
Function GetValueIfExists(Key As TKey, ByRef Succeeded As Boolean) As TValue
End Interface
The version with non-generic keys would allow code that was using code using non-structure key types to allow for arbitrary key variance, which would not be possible with a generic type parameter. One should not be allowed to use a mutable Dictionary(Of Cat, String) as a mutable Dictionary(Of Animal, String) since the latter would allow SomeDictionaryOfCat.Add(FionaTheFish, "Fiona"). But there's nothing wrong with using a mutable Dictionary(Of Cat, String) as an immutable Dictionary(Of Animal, String), since SomeDictionaryOfCat.Contains(FionaTheFish) should be considered a perfectly well-formed expression (it should return false, without having to search the dictionary, for anything that isn't of type Cat).
Unfortunately, the only way one will be able to actually use such an interface is if one wraps a Dictionary object in a class which implements the interface. Depending upon what you're doing, however, such an interface and the variance it allows might make it worth the effort.
If you are using ASP.NET MVC, you could leverage the RouteValueDictionary class that do the job.
public object this[string key]
{
get
{
object obj;
this.TryGetValue(key, out obj);
return obj;
}
set
{
this._dictionary[key] = value;
}
}
I used encapsulation to create an IDictionary with behavior very similar to an STL map, for those of you who are familiar with c++. For those who aren't:
indexer get {} in SafeDictionary below returns the default value if a key is not present, and adds that key to the dictionary with a default value. This is often the desired behavior, as you're looking up items that will appear eventually or have a good chance of appearing.
method Add(TK key, TV val) behaves as an AddOrUpdate method, replacing the value present if it exists instead of throwing. I don't see why m$ doesn't have an AddOrUpdate method and thinks throwing errors in very common scenarios is a good idea.
TL/DR - SafeDictionary is written so as to never throw exceptions under any circumstances, other than perverse scenarios, such as the computer being out of memory (or on fire). It does this by replacing Add with AddOrUpdate behavior and returning default instead of throwing NotFoundException from the indexer.
Here's the code:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class SafeDictionary<TK, TD>: IDictionary<TK, TD> {
Dictionary<TK, TD> _underlying = new Dictionary<TK, TD>();
public ICollection<TK> Keys => _underlying.Keys;
public ICollection<TD> Values => _underlying.Values;
public int Count => _underlying.Count;
public bool IsReadOnly => false;
public TD this[TK index] {
get {
TD data;
if (_underlying.TryGetValue(index, out data)) {
return data;
}
_underlying[index] = default(TD);
return default(TD);
}
set {
_underlying[index] = value;
}
}
public void CopyTo(KeyValuePair<TK, TD>[] array, int arrayIndex) {
Array.Copy(_underlying.ToArray(), 0, array, arrayIndex,
Math.Min(array.Length - arrayIndex, _underlying.Count));
}
public void Add(TK key, TD value) {
_underlying[key] = value;
}
public void Add(KeyValuePair<TK, TD> item) {
_underlying[item.Key] = item.Value;
}
public void Clear() {
_underlying.Clear();
}
public bool Contains(KeyValuePair<TK, TD> item) {
return _underlying.Contains(item);
}
public bool ContainsKey(TK key) {
return _underlying.ContainsKey(key);
}
public IEnumerator<KeyValuePair<TK, TD>> GetEnumerator() {
return _underlying.GetEnumerator();
}
public bool Remove(TK key) {
return _underlying.Remove(key);
}
public bool Remove(KeyValuePair<TK, TD> item) {
return _underlying.Remove(item.Key);
}
public bool TryGetValue(TK key, out TD value) {
return _underlying.TryGetValue(key, out value);
}
IEnumerator IEnumerable.GetEnumerator() {
return _underlying.GetEnumerator();
}
}
It could be a one-liner to check TryGetValue and return default value if it is false.
Dictionary<string, int> myDic = new Dictionary<string, int>() { { "One", 1 }, { "Four", 4} };
string myKey = "One"
int value = myDic.TryGetValue(myKey, out value) ? value : 100;
myKey = "One" => value = 1
myKey = "two" => value = 100
myKey = "Four" => value = 4
Try it online
Since .NET core 2.0 you can use:
myDict.GetValueOrDefault(someKeyKalue)
What about this one-liner that checks whether a key is present using ContainsKey and then returns either the normally retreived value or the default value using the conditional operator?
var myValue = myDictionary.ContainsKey(myKey) ? myDictionary[myKey] : myDefaultValue;
No need to implement a new Dictionary class that supports default values, simply replace your lookup statements with the short line above.
This question helped to confirm that the TryGetValue plays the FirstOrDefault role here.
One interesting C# 7 feature I would like to mention is the out variables feature, and if you add the null-conditional operator from C# 6 to the equation your code could be much more simple with no need of extra extension methods.
var dic = new Dictionary<string, MyClass>();
dic.TryGetValue("Test", out var item);
item?.DoSomething();
The downside of this is that you can't do everything inline like this;
dic.TryGetValue("Test", out var item)?.DoSomething();
If we'd need/want to do this we should code one extension method like Jon's.
Here is a version of #JonSkeet's for the world of C# 7.1 that also allows for an optional default to be passed in:
public static TV GetValueOrDefault<TK, TV>(this IDictionary<TK, TV> dict, TK key, TV defaultValue = default) => dict.TryGetValue(key, out TV value) ? value : defaultValue;
It may be more efficient to have two functions to optimize the case where you want to return default(TV):
public static TV GetValueOrDefault<TK, TV>(this IDictionary<TK, TV> dict, TK key, TV defaultValue) => dict.TryGetValue(key, out TV value) ? value : defaultValue;
public static TV GetValueOrDefault2<TK, TV>(this IDictionary<TK, TV> dict, TK key) {
dict.TryGetValue(key, out TV value);
return value;
}
Unfortunately C# doesn't (yet?) have a comma operator (or the C# 6 proposed semicolon operator) so you have to have an actual function body (gasp!) for one of the overloads.
Modern Answer
As of .NET Core 2.0, there is a built-in extension method with 2 overloads:
TValue GetValueOrDefault<TKey,TValue>(TKey)
TValue GetValueOrDefault<TKey,TValue>(TKey, TValue)
Usage:
var dict = new Dictionary<string, int>();
dict.GetValueOrDefault("foo"); // 0: the datatype's default
dict.GetValueOrDefault("foo", 2); // 2: the specified default
The first version returns null for nullable types, of course.
See the documentation for more detail.
In general I would support the answer from Jon Skeet, however I prefer an implementation where I can give the default value as parameter:
public static TValue GetValueOrDefault<TKey, TValue> (this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
{
if (dictionary.ContainsKey(key))
return dictionary[key];
else
return defaultValue;
}
No, because otherwise how would you know the difference when the key exists but stored a null value? That could be significant.