I have a Dictionary<dynamic, string>
and when checking if the dictionary contains a key, if the key is a string I would like to ignore the case. Is this possible?
Asked
Active
Viewed 8,352 times
1

Brian Campbell
- 161
- 1
- 12
-
2Why `dynamic`? How are you using a dictionary with dynamic as key? This sounds like an [XY problem](https://meta.stackexchange.com/q/66377/386424). What is your end goal? Why are you trying to do this? – Igor Jul 26 '18 at 15:22
-
2Use the Dictionary constructor that lets you pass your own `IEqualityComparer
` implementation. Similar to https://stackoverflow.com/a/46143745/17034. Do beware GetHashCode(), it needs to produce a case-insensitive value as well. Lowercase the string when appropriate. – Hans Passant Jul 26 '18 at 15:30 -
@HansPassant, I looked into that solution but was unable to implement IEqualityComparer with dynamic. I don't think that's possible in C#. – Brian Campbell Jul 26 '18 at 18:46
-
@Igor Why dynamic is a legitimate question. Without going into all of the details, I have a method that returns a collection of Dictionaries. I was originally hoping to use generic T as the key instead of dynamic, since the keys in a given dictionary will all be the same type. But the types of the keys will not be the same in all of the dictionaries, so T was not possible. I could use 'object' instead of 'dynamic' I guess, but I believe I still end up with the same problem. – Brian Campbell Jul 26 '18 at 18:53
-
@Igor I can give an example reason for C#/MVC; I have to write a filter that checks for the existence of a property in context.ModelState and if it exists validate it against a property of the auth token. The system is a brownfield and I don't know if anyone has written models with varying cases for this property. – C Bauer Oct 03 '18 at 13:33
2 Answers
2
You could add an extension to the Dictionary
which determines if the key is of type string, and if so, uses case insensitive comparison; otherwise, it uses the default comparison.
public static class DictionaryExtension
{
public static bool ContainsKeyIgnoreCase<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key)
{
bool? keyExists;
var keyString = key as string;
if (keyString != null)
{
// Key is a string.
// Using string.Equals to perform case insensitive comparison of the dictionary key.
keyExists =
dictionary.Keys.OfType<string>()
.Any(k => string.Equals(k, keyString, StringComparison.InvariantCultureIgnoreCase));
}
else
{
// Key is any other type, use default comparison.
keyExists = dictionary.ContainsKey(key);
}
return keyExists ?? false;
}
}
You can then use it like this:
var foo = new Foo();
var dictionary =
new Dictionary<dynamic, string>
{
{ 1, "One" }, // key is numeric
{ "Two", "Two" }, // key is string
{ foo, "Foo" } // key is object
};
dictionary.ContainsKeyIgnoreCase("two"); // Returns true
dictionary.ContainsKeyIgnoreCase("TwO"); // Returns true
dictionary.ContainsKeyIgnoreCase("aBc"); // Returns false
dictionary.ContainsKeyIgnoreCase(1); // Returns true
dictionary.ContainsKeyIgnoreCase(2); // Returns false
dictionary.ContainsKeyIgnoreCase(foo); // Returns true
dictionary.ContainsKeyIgnoreCase(new Foo()); // Returns false
Note:
The extension example above is using StringComparer.InvariantCultureIgnoreCase. You may need to modify the comparison for your needs.

Darren H
- 450
- 3
- 5
1
There's no reasonable way you could implement a case-insensitive get on a case-sensitive hash map.
Although you can create a new case-insensitive dictionary with the contents of an existing case-sensitive dictionary (if you're sure there are no case collisions):-
var oldDictionary = ...;
var comparer = StringComparer.OrdinalIgnoreCase;
var newDictionary = new Dictionary<string, int>(oldDictionary, comparer);
Let me know, if it works.