I am building the following class to manage a dictionary.
public class EnumDictionary<TKey, TValue>
{
private Dictionary<TKey, TValue> _Dict;
public EnumDictionary(Dictionary<TKey, TValue> Dict)
{
this._Dict = Dict;
}
public TKey GetValue(TValue value)
{
foreach (KeyValuePair<TKey, TValue> kvp in _Dict)
{
if (kvp.Value == value)
return kvp.Key;
}
throw new Exception("Undefined data type: " + value);
}
}
But I am getting an error "Operator '==' cannot be applied to operands of type 'TValue' and 'TValue'".
BTW, I am making this custom collection is because my dictionary has unique value, but I can't get key by value from a dictionary.
Any help is appreciated. Thank you.
Did you try using the Equals method?
if (kvp.Value.Equals(value))
I think this restriction is due to the fact that the == operator can't be used with all types. Take the following for instance:
struct Test
{
public int Value;
}
Given the above struct, the following code will not compile:
Test a, b;
a = b = new Test();
bool areEqual = a == b; // Operator '==' cannot be applied to
// operands of type 'Test' and 'Test'
However, all types have the Equals method, so calling that will work:
Test a, b;
a = b = new Test();
bool areEqual = a.Equals(b);
Fredrik is right; you need to use Equals as you can't presume to be able to use == for all types, since the operator isn't defined for every type.
Depending on your scenario, it might also make sense to add
where TValue : IEquatable<TValue>
as a generic type constraint on your class. The reason for this is that object.Equals accepts another object as a parameter, which means that if TValue is a value type it will be boxed. If it can be known to implement IEquatable<TValue>, on the other hand, then Equals can be resolved to IEquatable<TValue>.Equals*, which takes a TValue as a parameter and therefore won't require value types to be boxed.
I might also recommend that you rethink the internal structure of this class. As it currently stands, there's no reason you need this class at all, as you could easily add an extension method to IDictionary<TKey, TValue> to find a key by value via enumeration over the values. What I would do instead is store two dictionaries: a Dictionary<TKey, TValue> and a Dictionary<TValue, TKey>, so that two-way lookup is possible in O(1).
*By the way, in case you're curious, the reason you can't use IEquatable<T> (or any interface for that matter) to ensure that a type has implemented the == operator is that operators are static, and interfaces cannot provide static methods (and thus can't provide operators).
When you use generic comparsions I think you should implement a (x)CompareTo(Y) or a comparable class. Please correct me if im wrong.
you can use if (kvp.Value.Equals(value)) instead of ==.
Use the "where" condition on your generic types
class Dictionary<TKey,TVal>
where TKey: IComparable, IEnumerable
where TVal: MyI
{
public void Add(TKey key, TVal val)
{
}
}
from http://msdn.microsoft.com/en-us/library/6b0scde8%28VS.80%29.aspx
Don't create a new class. Create a extension method:
public static class DictionaryHelper
{
public static TKey GetKeyFromValue<TKey, TValue>(this IDictionary<TKey, TValue> instance, TValue value)
{
foreach (var kvp in instance)
{
if (kvp.Value.Equals(value))
return kvp.Key;
}
return default(TKey);
}
}
public class Example
{
public static void Main(string[] argv)
{
Dictionary<string, string> test = new Dictionary<string, string> { { "Mykey", "MyValue" }, { "Key1", "Value2" } };
string key = test.GetKeyFromValue("MyValue");
}
}
If you want this to be general purpose, then you will want the definition of equality to be configurable, just as it is in the dictionary for keys.
Have a property of type IEqualityComparer<TValue>, which is set in the constructor.
Then have a version of the constructor that makes the default EqualityComparer<TValue>.Default. This will work by calling Equals on the type in question.
public class EnumDictionary<TKey, TValue>
{
private Dictionary<TKey, TValue> _Dict;
private readonly IEqualityComparer<TValue> _cmp;
public EnumDictionary(Dictionary<TKey, TValue> Dict, IEqualityComparer<TValue> cmp)
{
this._Dict = Dict;
_cmp = cmp;
}
public EnumDictionary(Dictionary<TKey, TValue> Dict)
:this(Dict, IEqualityComparer<TValue>.Default){}
public TKey GetValue(TValue value)
{
foreach (KeyValuePair<TKey, TValue> kvp in _Dict)
{
if (cmp.Equals(kvp.Value, value))
return kvp.Key;
}
throw new Exception("Undefined data type: " + value);
}
}
Related
I have a Dictionary called baseDictionary. The key is a string and the values are the properties of a class called myData. In partiular the properties are: "age" (as int), "nationality" (as string) and "income" (as double).
So baseDictionary has some string as key and for each key a series of properties related to a specific person.
I want at some point to make a deep copy of this dictionary so that I can then work with this new copy without modifying the content of the original dictionary.
I have found an answer in stackoverflow where the following code is suggested to do this deep copy:
public static Dictionary<TKey, TValue>
CloneDictionaryCloningValues<TKey, TValue>(
Dictionary<TKey, TValue> original) where TValue : ICloneable
{
Dictionary<TKey, TValue> ret = new Dictionary<TKey, TValue>(
original.Count, original.Comparer);
foreach (KeyValuePair<TKey, TValue> entry in original)
{
ret.Add(entry.Key, (TValue) entry.Value.Clone());
}
return ret;
}
The problem is that I cannot understand how I should modify it to make it work with my dictionary. For example I tried:
public static Dictionary<string, myData> CloneDictionaryCloningValues<TKey, TValue>
(Dictionary<string, myData> original) where TValue : ICloneable
{
Dictionary<string, myData> ret = new Dictionary<string, myData>(original.Count,
original.Comparer);
foreach (KeyValuePair<string, myData> entry in original)
{
ret.Add(entry.Key, (myData)entry.Value.Clone());
}
return ret;
}
But I get the following error and it doesn't work.
Error 3 'Project2.myData does not contain a definition for 'Clone' and no extension method 'Clone' accepting a first argument of type
'Project2.myDatacould be found (are you missing a using directive or
an assembly reference?)
How can I fix the problem?
You don't need to change the CloneDictionaryCloningValues method at all, if you make the myData class implement the ICloneable interface:
public class myData : ICloneable {
// your code
public object Clone() {
// whatever you need to create a copy, for example:
return new myData() {
age = this.age,
nationality = this.nationality,
income = this.income
};
}
}
You can also rewrite/overload the method to take a cloning method instead of demanding the IClonable interface:
public static Dictionary<TKey, TValue> CloneDictionaryCloningValues<TKey, TValue>
(Dictionary<TKey, TValue> original, Func<TValue, TValue> clone)
{
Dictionary<TKey, TValue> ret = new Dictionary<TKey, TValue>(original.Count, original.Comparer);
foreach (KeyValuePair<TKey, TValue> entry in original) {
ret.Add(entry.Key, clone(Value));
}
return ret;
}
Then you call the method with a function that creates a copy of an item:
myCopy = CloneDictionaryCloningValues(myOriginal, item => {
// whatever you need to create a copy, for example:
return new myData() {
age = item.age,
nationality = item.nationality,
income = item.income
};
});
You should not modify the CloneDictionaryCloningValues() routine, just use it as it is. Because its generic, it will work with your keys (strings) and value class (mydata).
BUT:
To make this routine work your class must have a public Clone() routine i.e. implement the ICloneable interface.
As the function specifies: you need to implement ICloneable on the type myData
Also:
Keep the original code and simply pass your dictionary.
Rename the myData class to something more descriptive and have it start with an uppercase character
I have a dictionary where the key is a Tuple where the first item is a Date and the second item is a string. I would like the dictionary to be case insensitive.
I know that if the key was just a string I could pass StringComparer.OrdinalIgnoreCase as a parameter when declaring the dictionary, but this does not seem to work when the key is a Tuple.
Is there some way to specify the StringComparer to use on the second item of the Tuple?
Thanks
Use this overload of the Dictionary constructor, which allows you to specify a custom comparer for the keys. You would accompany this with creating a class that implements
IEqualityComparer<Tuple<string, DateTime>>
Which might look like this:
class CustomEqualityComparer : IEqualityComparer<Tuple<string, DateTime>>
{
public bool Equals(Tuple<string, DateTime> lhs, Tuple<string, DateTime> rhs)
{
return
StringComparer.CurrentCultureIgnoreCase.Equals(lhs.Item1, rhs.Item1)
&& lhs.Item2 == rhs.Item2;
}
public int GetHashCode(Tuple<string, DateTime> tuple)
{
return StringComparer.CurrentCultureIgnoreCase.GetHashCode(tuple.Item1)
^ tuple.Item2.GetHashCode();
}
}
There are no argument checks here, so please don't treat this as production code. Also, care needs to be taken so that the Equals and GetHashCode implementations satisfy the all-important condition that if two tuples compare equal, they must have the same hash code. When dealing with custom text comparisons it is easy to introduce bugs if not extra careful: for example, using ToLowerInvariant instead of ToLower above would be a bug (albeit one that might not surface for some time).
I needed this in a Dictionary<Tuple<>> wrapper, so I used #Jon 's code to create a generic version
public class TupleEqualityComparer<T1, T2> : IEqualityComparer<Tuple<T1, T2>>
{
private IEqualityComparer<T1> comparer1;
private IEqualityComparer<T2> comparer2;
public TupleEqualityComparer(IEqualityComparer<T1> comparer1, IEqualityComparer<T2> comparer2)
{
this.comparer1 = comparer1 ?? EqualityComparer<T1>.Default;
this.comparer2 = comparer2 ?? EqualityComparer<T2>.Default;
}
public bool Equals(Tuple<T1, T2> lhs, Tuple<T1, T2> rhs)
{
return comparer1.Equals(lhs.Item1, rhs.Item1) && comparer2.Equals(lhs.Item2, rhs.Item2);
}
public int GetHashCode(Tuple<T1, T2> tuple)
{
return comparer1.GetHashCode(tuple.Item1) ^ comparer2.GetHashCode(tuple.Item2);
}
}
public class Dictionary<TKey1, TKey2, TValue> : Dictionary<Tuple<TKey1, TKey2>, TValue>()
{
public Dictionary() : base() { }
public Dictionary(IEqualityComparer<TKey1> comparer1, IEqualityComparer<TKey2> comparer2) : base(new TupleEqualityComparer<TKey1, Tkey2>(comparer1, comparer2) { }
public TValue this[TKey1 key1, TKey2 key2]
{
get { return base[Tuple.Create(key1, key2)]; }
}
public void Add(TKey1 key1, TKey2 key2, TValue value)
{
base.Add(Tuple.Create(key1, key2), value);
}
public bool ContainsKey(TKey1 key1, TKey2 key2)
{
return base.ContainsKey(Tuple.Create(key1, key2));
}
public bool TryGetValue(TKey1 key1, TKey2 key2, out TValue value)
{
return base.TryGetValue(Tuple.Create(key1, key2), out value);
}
}
Usage
var dict = new Dictionary<string, DateTime, int>(
StringComparer.OrdinalIgnoreCase, null);
dict.Add("value1", DateTime.Now, 123);
Assert.IsTrue(dict.ContainsKey("VALUe1"));
Since the comparisons are going to be case-insensitive, you could use the toLower/toUpper method in the string side when making the tuples, and then always lower or upper the strings you'll have in the tuples used to retrive/compare entries in the dictionary.
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;
}
}
}
I'm trying to write an extension method to insert data into a dictionary of dictionaries defined as follows:
items=Dictionary<long,Dictionary<int,SomeType>>()
What I have so far is:
public static void LeafDictionaryAdd<TKEY1,TKEY2,TVALUE>(this IDictionary<TKEY1,IDictionary<TKEY2,TVALUE>> dict,TKEY1 key1,TKEY2 key2,TVALUE value)
{
var leafDictionary =
dict.ContainsKey(key1)
? dict[key1]
: (dict[key1] = new Dictionary<TKEY2, TVALUE>());
leafDictionary.Add(key2,value);
}
but the compiler doesn't like it. The statement:
items.LeafDictionaryAdd(longKey, intKey, someTypeValue);
gives me a type inference error.
For the statement:
items.LeafDictionaryAdd<long, int, SomeType>(longKey, intKey, someTypeValue);
I get "...does not contain a definition for... and the best extension method overload has some invalid arguments.
What am I doing wrong?
Some inventive generic usage ;-p
class SomeType { }
static void Main()
{
var items = new Dictionary<long, Dictionary<int, SomeType>>();
items.Add(12345, 123, new SomeType());
}
public static void Add<TOuterKey, TDictionary, TInnerKey, TValue>(
this IDictionary<TOuterKey,TDictionary> data,
TOuterKey outerKey, TInnerKey innerKey, TValue value)
where TDictionary : class, IDictionary<TInnerKey, TValue>, new()
{
TDictionary innerData;
if(!data.TryGetValue(outerKey, out innerData)) {
innerData = new TDictionary();
data.Add(outerKey, innerData);
}
innerData.Add(innerKey, value);
}
Try to use a concrete type:
public static void LeafDictionaryAdd<TKEY1,TKEY2,TVALUE>(this IDictionary<TKEY1, Dictionary<TKEY2,TVALUE>> dict,TKEY1 key1,TKEY2 key2,TVALUE value)
see the Dictionary<TKEY2,TVALUE> instead of IDictionary<TKEY2,TVALUE>
I'm guessing that this is a covariance / contravariance issue. Your method signature is expecting an IDictionary of IDcitionaries, but you're passing it an IDictionary of Dictionary. Try using a concrete Dictionary instead in your method signature, for the inner Dictionary.
If you specify an IDictionary on your Parameter list for the Extension method,
then your items will not match that.
Either change your Extension to
public static void LeafDictionaryAdd<TKEY1,TKEY2,TVALUE>(
this IDictionary<TKEY1, Dictionary<TKEY2,TVALUE>> dict,
TKEY1 key1,
TKEY2 key2,
TVALUE value)
OR Try and cast your items to
((IDictionary<long, IDictionary<int, YourType>>)items).LeafDictionaryAdd(l, i, o);
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.