"Verbose Dictionary" in C#, 'override new' this[] or implement IDictionary - c#

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?

Related

More specific exception messages

Is there any way in C# to improve exception messages?
I'm tired of getting an unexpected error like Index was out of range or Key not found in dictionary without the most important informations.
I mean, if index was out of bounds, tell me what was the value of index.
If the key does not exist, tell me what key does not exist.
I know I can use try catch with more detailed message.
try
{
dictionary[key] = value;
}
catch (KeyNotFoundException)
{
Console.WriteLine("Key not found. Key value: " + key)
}
However I'm quite tired of this, especially since recreating bugs is not always easy.
EDIT:
I've created simple dictionary inheritance.
using System.Collections.Generic;
public class ExcDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
new public TValue this[TKey key]
{
get
{
try
{
return base[key];
}
catch (KeyNotFoundException)
{
throw new KeyNotFoundException("KeyNotFoundException: The given key (" + key.ToString() + ") was not present in the dictionary.");
}
}
set
{
base[key] = value;
}
}
}
A possible solution is to use a wrapper class around Dictionary.
Something like:
public class CustomDictionary<TKey, TValue>
{
private readonly Dictionary<TKey, TValue> _dictionary;
public CustomDictionary(Dictionary<TKey, TValue> dictionary)
{
_dictionary = dictionary;
}
public TValue this[TKey key]
{
get
{
try
{
return _dictionary[key];
}
catch (KeyNotFoundException)
{
Console.WriteLine("CustomDictionary: key not found in GET. Key value: " + key);
throw; // could also 'return default;' instead, depending on what you want to get when key is not found.
}
}
set
{
try
{
_dictionary[key] = value;
}
catch (KeyNotFoundException)
{
Console.WriteLine("CustomDictionary: key not found in SET. Key value: " + key);
}
}
}
}
Notes:
you can avoid the try catch statements by testing if the key is contained in the dictionary instead. Try catch block can be costly in performance. See doc on ContainsKey: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.containskey?view=net-6.0
I would also define an extension method .ToCustomDictionary like the Linq method .ToDictionary as a helper to make this class easy easy to use in your code.
Some doc ref:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/using-indexers.
This is a very simple "decorator" around the Dictionary, and if you need to access other Dictionary methods, you could either just create them, or expose the original dictionary as a public instead of a private field.
Alternative solution:
Create your SafeSet extension method:
public static class DictionaryExtensions
{
public static void SafeSet<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
if (dictionary.ContainsKey(key))
{
dictionary[key] = value;
}
else
{
// Here you can just add the missing key without any error!
dictionary.Add(key, value);
// of course you could also display an error message / throw your own exception if you want.
}
}
}
// Usage:
var anyDictionary = new Dictionary<int, string>();
anyDictionary.SafeSet(42, "I'll be added to the dictionary");
anyDictionary.SafeSet(42, "Now I'll replace the existing value as usual.");

Convenience method to find or add value to generic dictionary

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

remove specific values from multi value dictionary

I've seen posts here on how to make a dictionary that has multiple values per key, like one of the solutions presented in this link:
Multi Value Dictionary
it seems that I have to use a List<> as the value for the keys, so that a key can store multiple values.
the solution in the link is fine if you want to add values. But my problem now is how to remove specific values from a single key.
I have this code for adding values to a dictionary:
private Dictionary<TKey, List<TValue>> mEventDict;
// this is for initializing the dictionary
public void Subscribe(eVtEvtId inEvent, VtEvtDelegate inCallbackMethod)
{
if (mEventDict.ContainsKey(inEvent))
{
mEventDict[inEvent].Add(inCallbackMethod);
}
else
{
mEventDict.Add(inEvent, new List<TValue>() { v });
}
}
// this is for adding values to the dictionary.
// if the "key" (inEvent) is not yet present in the dictionary,
// the key will be added first before the value
my problem now is removing a specific value from a key. I have this code:
public void Unsubscribe(eVtEvtId inEvent, VtEvtDelegate inCallbackMethod)
{
try
{
mEventDict[inEvent].Remove(inCallbackMethod);
}
catch (ArgumentNullException)
{
MessageBox.Show("The event is not yet present in the dictionary");
}
}
basically, what I did is just replace the Add() with Remove() . Will this work?
Also, if you have any problems or questions with the code (initialization, etc.), feel free to ask.
Thanks for the advice.
TylerOhlsen's answer is a step in the right direction, but it has 6 key lookups (calls to Remove, ContainsKey, and the indexer). This can be reduced to three by using TryGetValue:
private Dictionary<TKey, List<TValue>> mEventDict;
public void Subscribe(TKey inEvent, TValue inCallbackMethod)
{
List<TValue> list;
if (mEventDict.TryGetValue(inEvent, out list))
list.Add(inCallbackMethod);
else
mEventDict.Add(inEvent, new List<TValue> { inCallbackMethod });
}
public bool Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
List<TValue> list;
if (!mEventDict.TryGetValue(inEvent, out list))
return false;
bool removed = list.Remove(inCallbackMethod);
if (list.Count == 0)
mEventDict.Remove(inEvent);
return removed;
}
If you don't care about removing empty lists:
public bool Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
List<TValue> list;
if (!mEventDict.TryGetValue(inEvent, out list))
return false;
return list.Remove(inCallbackMethod);
}
If you don't need to report whether the item was in the list (and therefore removed from it), change the return type to void, and (in the first version) get rid of the removed variable.
Will it work? Not exactly the way you intended...
Your method parameters will need to be of the generic types.
List(T).Remove does not throw an ArgumentNullException.
You might want to clean up your dictionary if your list becomes empty.
The caller might not care if the callback was ever subscribed when they unsubscribe, but you have that information so you might as well return it. This information could be helpful for troubleshooting/logging purposes.
This is what I would recommend...
private Dictionary<TKey, List<TValue>> mEventDict;
public void Subscribe(TKey inEvent, TValue inCallbackMethod)
{
if (!mEventDict.ContainsKey(inEvent))
mEventDict.Add(inEvent, new List<TValue>());
mEventDict[inEvent].Add(inCallbackMethod);
}
public bool Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
if (!mEventDict.ContainsKey(inEvent))
return false;
bool removed = mEventDict[inEvent].Remove(inCallbackMethod);
if (mEventDict[inEvent].Count == 0)
mEventDict.Remove(inEvent);
return removed;
}
NOTE: I have not tested this code, so just try it out. Also, this code is not thread safe.
#phoog - so I want to keep the Unsubscribe method as void . After modifying your code, this is what I came up with...
public void Unsubscribe(TKey inEvent, TValue inCallbackMethod)
{
List<TValue> list;
bool mRemoved = false.
if (mEventDict.TryGetValue(inEvent, out list))
{
list.Remove(inCallbackMethod);
mRemoved = true;
}
}
is the listRemoved variable necessary? But then again, I think nothing will happen if the inCallbackMethod cannot be found in the list.

Need an IDictionary<TKey,TValue> implementation that will allow a null key

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

Is there a more elegant way of adding an item to a Dictionary<> safely?

I need to add key/object pairs to a dictionary, but I of course need to first check if the key already exists otherwise I get a "key already exists in dictionary" error. The code below solves this but is clunky.
What is a more elegant way of doing this without making a string helper method like this?
using System;
using System.Collections.Generic;
namespace TestDictStringObject
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> currentViews = new Dictionary<string, object>();
StringHelpers.SafeDictionaryAdd(currentViews, "Customers", "view1");
StringHelpers.SafeDictionaryAdd(currentViews, "Customers", "view2");
StringHelpers.SafeDictionaryAdd(currentViews, "Employees", "view1");
StringHelpers.SafeDictionaryAdd(currentViews, "Reports", "view1");
foreach (KeyValuePair<string, object> pair in currentViews)
{
Console.WriteLine("{0} {1}", pair.Key, pair.Value);
}
Console.ReadLine();
}
}
public static class StringHelpers
{
public static void SafeDictionaryAdd(Dictionary<string, object> dict, string key, object view)
{
if (!dict.ContainsKey(key))
{
dict.Add(key, view);
}
else
{
dict[key] = view;
}
}
}
}
Just use the indexer - it will overwrite if it's already there, but it doesn't have to be there first:
Dictionary<string, object> currentViews = new Dictionary<string, object>();
currentViews["Customers"] = "view1";
currentViews["Customers"] = "view2";
currentViews["Employees"] = "view1";
currentViews["Reports"] = "view1";
Basically use Add if the existence of the key indicates a bug (so you want it to throw) and the indexer otherwise. (It's a bit like the difference between casting and using as for reference conversions.)
If you're using C# 3 and you have a distinct set of keys, you can make this even neater:
var currentViews = new Dictionary<string, object>()
{
{ "Customers", "view2" },
{ "Employees", "view1" },
{ "Reports", "view1" },
};
That won't work in your case though, as collection initializers always use Add which will throw on the second Customers entry.
What's wrong with...
dict[key] = view;
It'll automatically add the key if it's non-existent.
simply
dict[key] = view;
From the MSDN documentation of Dictionary.Item
The value associated with the
specified key. If the specified key is
not found, a get operation throws a
KeyNotFoundException, and a set
operation creates a new element with
the specified key.
My emphasis
As usual John Skeet gets in there with lighting speed with the right answer, but interestingly you could also have written your SafeAdd as an Extension Method on IDictionary.
public static void SafeAdd(this IDictionary<K, T>. dict, K key, T value)...
Although using the indexer is clearly the right answer for your specific problem, another more general answer to the problem of adding additional functionality to an existing type would be to define an extension method.
Obviously this isn't a particularly useful example, but something to bear in mind for the next time you find a real need:
public static class DictionaryExtensions
{
public static void SafeAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict,
TKey key, TValue value)
{
dict[key] = value;
}
}

Categories