How do I store comparison functions in a Dictionary? - c#

I would like to have my comparison functions accessible by using a key. This is what I have tried. I think my problem is how I'm declaring the type for the dictionary value.
internal static int CompareUsersByEmail(MembershipUser a, MembershipUser b)
{
// imagine null checking happening here.
return string.Compare(a.Email, b.Email, true);
}
public static void Sort(List<MembershipUser> list, string expression) {
// I can do this
list.Sort(CompareUsersByEmail);
// but not this
Dictionary<string, Func<MembershipUser, MembershipUser, int>> compareFns;
compareFns = new Dictionary<string, Func<MembershipUser, MembershipUser, int>>();
compareFns["Email"] = CompareUsersByEmail;
list.Sort(compareFns[expression]); // where expression would be "Email"
}
Is this possible?

Change your dictionary type to:
Dictionary<string, Comparison<MembershipUser>> compareFns;
I believe it will then work with no other changes. The method group conversion to Comparison<MembershipUser> will still work, and now you can call List<T>.Sort(Comparison<T>).

Related

How can I refactor this C# code currently using Dictionarys to have even less redundancy and be more typesafe?

Because of business decisions which are above my paygrade, I need to parse and merge multiple XML files.
In order to cut down on redundant code, I have this map:
private static readonly Dictionary<string, Type> listTypeByFileName = new Dictionary<string, Type> {
{"a.xml", typeof(List<A>)},
{"b.xml", typeof(List<B>)},
{"c.xml", typeof(List<C>)},
{"d.xml", typeof(List<D>)},
// etc.
};
Because how this map gets used, after downloading and parsing all the XMLs, the result is of type Dictionary<string, object> where the key is the same as the keys in the above map and the value is of the type specified in the map, as result of executing this code with DownloadFiles(config):
private static Dictionary<string, object> DownloadFiles(IConfigurationRoot config) {
Dictionary<string, object> dataListByFileNames = new Dictionary<string, object>();
listTypeByFileName.Keys.ToList()
.ForEach(name => dataListByFileNames.Add(name, DownloadData(name, config)));
return dataListByFileNames;
}
private static object DownloadData(string name, IConfigurationRoot config) {
_ = listTypeByFileName.TryGetValue(name, out Type listType);
return new XmlSerializer(listType, new XmlRootAttribute("Document"))
.Deserialize(new StringReader(DownloadFromBlobStorage(name, config).ToString()));
}
private static CloudBlockBlob DownloadFromBlobStorage(string filetoDownload, IConfigurationRoot config) {
return CloudStorageAccount.Parse(config["AzureWebJobsStorage"])
.CreateCloudBlobClient()
.GetContainerReference(config["BlobStorageContainerName"])
.GetBlockBlobReference(filetoDownload);
First question: Is there a way I can make the return more typesafe? Perhaps using parameterized types?
The second part of the problem is actually consuming this Dictionary.
For each type in this Dictionary, I now need a function like:
private void AddA(Dictionary<string, object> dataByFileNames) {
if (dataByFileNames.TryGetValue("a.xml", out object data)) {
List<A> aList = (List<A>)data;
aList.ForEach(a =>
doSomethingWithA(a);
);
}
}
private void AddB(Dictionary<string, object> dataByFileNames) {
if (dataByFileNames.TryGetValue("b.xml", out object data)) {
List<B> bList = (List<B>)data;
bList.ForEach(b =>
doSomethingWithB(b);
);
}
}
// etc.
As I already have the list of filenames to types (top of this question), I feel there should be some way to abstract the above so it does not need to be repeated again and again and again.
Note, it may be significant that every type (A, B, C, D, etc. all have a property string Id which will be definitely be needed for all doStringWithX() methods... if useful, I can create an interface to get this. It is okay if I need to caste to the correct type within each doStringWithX() or when invoking each of these methods.c
First, instead of storing the List<T> type in the dictionary, just store the underlying generic type:
private static readonly Dictionary<string, Type> listTypeByFileName = new Dictionary<string, Type> {
{"a.xml", typeof(A)},
{"b.xml", typeof(B)}
// etc.
That's going to make future steps a little bit easier. When deserializing, create the generic list type. After getting the type from the dictionary, you can do:
var listType = typeof(List<>).MakeGenericType(typeRetrievedFromDictionary);
Once you've deserialized it, cast it as IList. That's effectively casting it as a list of object. That's okay. Because you deserialized using a specific type, every item in the list will be of the expected type.
Create a dictionary for the type-safe methods you want to invoke on every time in list.
Dictionary<Type, Action<object>> methodsToInvokeByType;
Add methods to the dictionary:
doSometingMethods.Add(typeof(A), dataItem => DoSomethingWithA((A)dataItem));
doSometingMethods.Add(typeof(B), dataItem => DoSomethingWithB((B)dataItem));
Now, once you've got your IList full of objects, you retrieve the type-safe method to invoke:
var methodToInvoke = methodsToInvokeByType[typeRetrievedFromDictionary];
Then do this:
foreach(object itemInList in list) // this is your deserialized list cast as IList
{
methodToInvoke(itemInList);
}
So if the type is A, you'll be invoking
DoSomethingWithA((A)itemInList)
It's not pretty. Bridging between code that uses objects and Type and type-safe generic code can be messy. But ultimately the goal is that whatever those final methods are - DoSomethingWithA, DoSomethingWithB, etc., at least those are type-safe.
You can simplify some more:
Create a class that deserializes a list and passes it off to a method for processing, and an interface:
public interface IXmlFileProcessor
{
void Process(byte[] xmlFile);
}
public class XmlFileProcessor<T> : IXmlFileProcessor
{
private readonly Action<T> _doSomething;
public XmlFileProcessor(Action<T> doSomething)
{
_doSomething = doSomething;
}
public void Process(byte[] xmlFile) // or string or whatever
{
// deserialize into a List<T>
foreach (T item in deserializedList)
_doSomething(item);
}
}
Then create a Dictionary<Type, IXmlFileProcessor> and populate it:
fileProcessors.Add(typeof(A), new XmlFileProcessor<A>(SomeClass.DoSomethingWithA));
fileProcessors.Add(typeof(B), new XmlFileProcessor<B>(SomeClass.DoSomethingWithB));
That approach (injecting the Action) is intended to keep the "do something" method decoupled from the class responsible for deserialization. DoSomething could also be a generic method in XmlFileProcessor<T>. There are different ways to compose those classes and add them to that dictionary. But either way, having determined the type, you just retrieve the correct type-specific processor from the dictionary, pass your file to it, and it does the rest.
That approach bridges the generic/non-generic gap by making the class - XmlFileProcessor<T> - generic, but having it implement a non-generic interface. It works as long as you take steps (using the dictionary) to ensure that you're selecting the correct implementation for whatever type you're deserializing.

Add element to dictionary where key is property of value

I am trying to build a dictionary where the key is a property of the value object. However I would like to construct the value object in the dictionary's add method. Is there a way to do this without using an intermediate variable?
For example I would like to do the following, but of course the key value isn't available when needed.
Dictionary<int,SomeComplexObject> dict = new Dicionary<int,SomeComplexObject>{
{someComplexObject.Key, new SomeComplexObject {Key = 1, Name = "FooBar"},
{someComplexObject.Key, new SomeComplexObject {Key = 2, Name = "FizzBang"}
};
Do I have to do it this ugly way:
Dictionary<int,SomeComplexObject> dict = new Dicionary<int,SomeComplexObject>();
SomeComplexObject value1 = new SomeComplexObject{Key=1,Name = "FooBar"};
dict.Add(value1.Key,value1);
SomeComplexObject value2 = new SomeComplexObject{Key=2,Name = "FizzBang"};
dict.Add(value.Key,value2);
I don't think this is the same question as
How to use an object's identity as key for Dictionary<K,V>
because I am not asking specifically about the key of a dictionary but if there is a way to have access to a objects property when the object is not being created until later in the methods parameter list.
I don't think an extension method (as proposed in comments) is really what you want here, as it's only a partial solution. I.e. you would have to write a new extension method for each dictionary value type you wanted to use, which negates the whole point of asking for a general solution.
Instead, it seems to me that you probably just want to subclass the Dictionary<TKey, TValue> type to add your own custom behavior. You can do this just once, in a general-purpose way, so that you can provide a delegate for each type you expect to have to use this way.
That would look something like this:
class KeyExtractorDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
private readonly Func<TValue, TKey> _extractor;
public KeyExtractorDictionary(Func<TValue, TKey> extractor)
{
_extractor = extractor;
}
public void Add(TValue value)
{
Add(_extractor(value), value);
}
}
You would use it something like this:
class Data
{
public int Key { get; }
public string Name { get; }
public Data(int key, string name)
{
Key = key;
Name = name;
}
}
class Program
{
static void Main(string[] args)
{
KeyExtractorDictionary<int, Data> dictionary =
new KeyExtractorDictionary<int, Data>(d => d.Key)
{
new Data(1, "FooBar"),
new Data(2, "FizzBang")
};
}
}
(I used Data as the value type type, instead of T as you seem to have used in your question, to avoid confusing the type name with a generic type parameter.)
In this way, you only have to write the class once, regardless of how many different types you might want to use for this type of dictionary. You can then pass the class constructor the key extractor delegate appropriate for the current value type of the dictionary.
Note that doing it this way, you also can take advantage of C#'s collection initializer syntax. Since your new type has an Add() method that takes just the value for each dictionary entry, the compiler will translate a collection initializer into the correct calls to add each object to the dictionary.
This allows for a dictionary in which you can still retrieve objects solely by the key value (using a custom comparer would require an instance of the value type with the same key you're looking for), while still addressing the broader concerns of not having to specify the key explicitly when adding objects, and of generality and reuse.
You can try an extension method, which is less invasive:
public static void AddByKey<TKey, T>(this Dictionary<TKey, T> dictionary, T item)
{
dictionary.Add(item.Key, item);
}
But to really do this correctly you also need an interface to protect you against types without the Key property:
public interface ItemWithKey<TKey>
{
TKey Key { get; }
}
public static void AddByKey<TKey, T>(this Dictionary<TKey, T> dictionary, T item)
where T : ItemWithKey<TKey>
{
dictionary.Add(item.Key, item);
}
I don't have a compiler in my hands right now, I cannot test this code so minor errors may have slipped in. I hope you get the idea and usefulness if you have those cases a lot in your code. Otherwise, I'd advise to go with the ugly working code you already have.
You can use the ToDictionary() extension method to solve this issue. Here is a complete example that can be run in LINQPad.
void Main()
{
Dictionary<int, SomeComplextObject> dict = new List<SomeComplextObject>{
{new SomeComplextObject {Key = 1, Name = "FooBar"}},
{new SomeComplextObject {Key = 2, Name = "FizzBangr"}}
}.ToDictionary(k =>k.Key);
//Dump Dictionary to LINQPad's result window.
dict.Dump();
}
public class SomeComplextObject{
public int Key { get; set; }
public string Name {get;set;}
}
I would like to propose a different slightly different way of going about this, it's similar to #pid 's method but instead of an interface uses a linq expression. First built your list of objects, then use an extension method to add them to your dictionary in a single simple step. In my mind this is also a little more intuitive to read, your program would look like:
class Program
{
static void Main(string[] args)
{
List<SomeComplexObject> toAdd = new List<SomeComplexObject>() {
new SomeComplexObject(1,"FooBar"),
new SomeComplexObject(2,"FizzBang")
};
var dict = new Dictionary<int,SomeComplexObject>();
dict.AddByKey(toAdd, item => item.Key);
}
}
Where AddByKey is an extension method that uses linq to basically pass a reference to that property and would look like this:
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
public static class DictionaryExtensions
{
/// <summary>
/// This extension method was built for when you want to add a list of items to a dictionary as the values, and you want to use one of those
/// items' properties as the key. It uses LINQ to check by property reference.
/// </summary>
/// <typeparam name="TKey"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="dict"></param>
/// <param name="targets"></param>
/// <param name="propertyToAdd"></param>
public static void AddByKey<TKey, TValue>(this Dictionary<TKey, TValue> dict, IEnumerable<TValue> targets, Expression<Func<TValue, TKey>> propertyToAdd)
{
MemberExpression expr = (MemberExpression)propertyToAdd.Body;
PropertyInfo prop = (PropertyInfo)expr.Member;
foreach (var target in targets)
{
var value = prop.GetValue(target);
if (!(value is TKey))
throw new Exception("Value type does not match the key type.");//shouldn't happen.
dict.Add((TKey)value, target);
}
}
}
And if you wanted to simplify the calling code even further, instead of returning void, you could have that extension method return the originally passed dictionary, and then your calling code could be collapsed to:
var dict = new Dictionary<int,SomeComplexObject>().AddByKey(toAdd, item => item.Key);

Using Dictionary with nested Generics from Generic Method [duplicate]

I'd like to create a Dictionary object, with string Keys, holding values which are of a generic type. I imagine that it would look something like this:
Dictionary<string, List<T>> d = new Dictionary<string, List<T>>();
And enable me to add the following:
d.Add("Numbers", new List<int>());
d.Add("Letters", new List<string>());
I know that I can do it for a list of strings, for example, using this syntax:
Dictionary<string, List<string>> d = new Dictionary<string, List<string>>();
d.Add("Key", new List<string>());
but I'd like to do it for a generic list if possible...
2 questions then:
Is it possible?
What's the syntax?
EDIT: Now I've reread the question...
You can't do this, but a custom collection would handle it to some extent. You'd basically have a generic Add method:
public void Add<T>(string key, List<T> list)
(The collection itself wouldn't be generic - unless you wanted to make the key type generic.)
You couldn't extract values from it in a strongly typed manner though, because the compiler won't know which type you've used for a particular key. If you make the key the type itself, you end with a slightly better situation, but one which still isn't supported by the existing collections. That's the situation my original answer was responding to.
EDIT: Original answer, when I hadn't quite read the question correctly, but which may be informative anyway...
No, you can't make one type argument depend on another, I'm afraid. It's just one of the things one might want to express in a generic type system but which .NET's constraints don't allow for. There are always going to be such problems, and the .NET designers chose to keep generics relatively simple.
However, you can write a collection to enforce it fairly easily. I have an example in a blog post which only keeps a single value, but it would be easy to extend that to use a list.
Would something like this work?
public class GenericDictionary
{
private Dictionary<string, object> _dict = new Dictionary<string, object>();
public void Add<T>(string key, T value) where T : class
{
_dict.Add(key, value);
}
public T GetValue<T>(string key) where T : class
{
return _dict[key] as T;
}
}
Basically it wraps all the casting behind the scenes for you.
How about Dictionary<string, dynamic>? (assuming you're on C# 4)
Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>();
Source: https://stackoverflow.com/a/5038029/3270733
I prefer this way of putting generic types into a collection:
interface IList
{
void Add (object item);
}
class MyList<T> : List<T>, IList
{
public void Add (object item)
{
base.Add ((T) item); // could put a type check here
}
}
class Program
{
static void Main (string [] args)
{
SortedDictionary<int, IList>
dict = new SortedDictionary<int, IList> ();
dict [0] = new MyList<int> ();
dict [1] = new MyList<float> ();
dict [0].Add (42);
dict [1].Add ("Hello"); // Fails! Type cast exception.
}
}
But you do lose the type checks at compile time.
I came to a type safe implementation using ConditionalWeakTable.
public class FieldByType
{
static class Storage<T>
where T : class
{
static readonly ConditionalWeakTable<FieldByType, T> table = new ConditionalWeakTable<FieldByType, T>();
public static T GetValue(FieldByType fieldByType)
{
table.TryGetValue(fieldByType, out var result);
return result;
}
public static void SetValue(FieldByType fieldByType, T value)
{
table.Remove(fieldByType);
table.Add(fieldByType, value);
}
}
public T GetValue<T>()
where T : class
{
return Storage<T>.GetValue(this);
}
public void SetValue<T>(T value)
where T : class
{
Storage<T>.SetValue(this, value);
}
}
It can be used like this:
/// <summary>
/// This class can be used when cloning multiple related objects to store cloned/original object relationship.
/// </summary>
public class CloningContext
{
readonly FieldByType dictionaries = new FieldByType();
public void RegisterClone<T>(T original, T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
dictionary = new Dictionary<T, T>();
dictionaries.SetValue(dictionary);
}
dictionary[original] = clone;
}
public bool TryGetClone<T>(T original, out T clone)
{
var dictionary = dictionaries.GetValue<Dictionary<T, T>>();
if (dictionary == null)
{
clone = default(T);
return false;
}
return dictionary.TryGetValue(original, out clone);
}
}
See also this question where the type of the values is stored in as a generic parameter of the keys.
We're using lots of reflection to create an extensible administration tool. We needed a way to register items in the global search in the module definition. Each search would return results in a consistent way, but each one had different dependencies. Here's an example of us registering search for a single module:
public void ConfigureSearch(ISearchConfiguration config)
{
config.AddGlobalSearchCallback<IEmploymentDataContext>((query, ctx) =>
{
return ctx.Positions.Where(p => p.Name.Contains(query)).ToList().Select(p =>
new SearchResult("Positions", p.Name, p.ThumbnailUrl,
new UrlContext("edit", "position", new RouteValueDictionary(new { Id = p.Id }))
));
});
}
In the background during module registration, we iterate over every module and add the Func to a SearchTable with an instance of:
public class GenericFuncCollection : IEnumerable<Tuple<Type, Type, Object>>
{
private List<Tuple<Type, Type, Object>> objects = new List<Tuple<Type, Type, Object>>();
/// <summary>
/// Stores a list of Func of T where T is unknown at compile time.
/// </summary>
/// <typeparam name="T1">Type of T</typeparam>
/// <typeparam name="T2">Type of the Func</typeparam>
/// <param name="func">Instance of the Func</param>
public void Add<T1, T2>(Object func)
{
objects.Add(new Tuple<Type, Type, Object>(typeof(T1), typeof(T2), func));
}
public IEnumerator<Tuple<Type, Type, object>> GetEnumerator()
{
return objects.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return objects.GetEnumerator();
}
}
Then when we finally call it, we do it with reflection:
var dependency = DependencyResolver.Current.GetService(search.Item1);
var methodInfo = search.Item2.GetMethod("Invoke");
return (IEnumerable<SearchResult>)methodInfo.Invoke(search.Item3, new Object[] { query, dependency });
I didn't find what I was looking for here but after reading I think it might be what is being asked for so an attempt to answer.
The problem is that when you use Dictionary it is a closed constructed type and all elements must be of the TValue type. I see this question in a number of places without a good answer.
Fact is that I want indexing but each element to have a different type and based on the value of TKey we already know the type. Not trying to get around the boxing but trying to simply get more elegant access something like DataSetExtensions Field. And don't want to use dynamic because the types are known and it is just not wanted.
A solution can be to create a non generic type that does not expose T at the class level and therefore cause the TValue part of the dictionary to be closed constructed. Then sprinkle in a fluent method to help initialization.
public class GenericObject
{
private object value;
public T GetValue<T>()
{
return (T)value;
}
public void SetValue<T>(T value)
{
this.value = value;
}
public GenericObject WithValue<T>(T value)
{
this.value = value;
return this;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, GenericObject> dict = new Dictionary<string, GenericObject>();
dict["mystring"] = new GenericObject().WithValue<string>("Hello World");
dict["myint"] = new GenericObject().WithValue<int>(1);
int i = dict["myint"].GetValue<int>();
string s = dict["mystring"].GetValue<string>();
}
}
Other posibility it's to use the variable dynamic.
For example:
Dictionary<string, List<dynamic>> d = new Dictionary<string, List<dynamic>>();
d.Add("Key", new List<dynamic>());
the variable dynamic resolve the type on runtime.
No, but you can use object instead of generic type.
Long answer:
The current version of C# will not allow you to make entries of generic type in a dictionary. Your options are either a) create a custom class that is the same as a dictionary except allow it to accept generic types, or b) make your Dictionary take values of type object. I find option b to be the simpler approach.
If you send lists of specific types, then when you go to process the lists you will have to test to see what kind of list it is. A better approach is to create lists of objects; this way you can enter integers, strings, or whatever data type you want and you don't necessarily have to test to see what type of object the List holds. This would (presumably) produce the effect you're looking for.
Here is a short console program that does the trick:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace dictionary
{
class Program
{
static void Main(string[] args)
{
Dictionary<string, object> dic = new Dictionary<string, object>();
var lstIntList = new List<object>();
var lstStrings = new List<object>();
var lstObjects = new List<object>();
string s = "";
lstIntList.Add(1);
lstIntList.Add(2);
lstIntList.Add(3);
lstStrings.Add("a");
lstStrings.Add("b");
lstStrings.Add("c");
dic.Add("Numbers", lstIntList);
dic.Add("Letters", lstStrings);
foreach (KeyValuePair<string, object> kvp in dic)
{
Console.WriteLine("{0}", kvp.Key);
lstObjects = ((IEnumerable)kvp.Value).Cast<object>().ToList();
foreach (var obj in lstObjects)
{s = obj.ToString(); Console.WriteLine(s);}
Console.WriteLine("");
}
Console.WriteLine("");
Console.WriteLine("press any key to exit");
Console.ReadKey();
}//end main
}
}
One of the way is to create a Dictionary value with type "object" like:
Dictionary<string, object> d = new Dictionary<string, object>();
So, here object datatype is used as a generic datatype, you can put anything in this as a value.
Or it's possible to use generic Type like this
public static void SafeUpdateInDictionary<T, L>(T DictionaryToBeUpdated, string Key, L Value) where T : Dictionary<string, L>
{
if (DictionaryToBeUpdated != null)
{
if(Value != null)
{
if (!DictionaryToBeUpdated.ContainsKey(Key))
DictionaryToBeUpdated.Add(Key, Value);
else
DictionaryToBeUpdated[Key] = Value;
}
}
}

Create a static dictionary object, filled with values from the database

I would like to have a dictionary object contains string keys and values, which are generated from the database. But, I only need to run once when page loads. (C# .NET)
In which way can I do that? I tried the following:
public static class GlobalVar
{
static Dictionary<string, string> GenerateLoginStatus(Dictionary<string, string> List)
{
string Query = "SELECT * FROM LoginStatus";
DataTable Types = MyAdoHelper.ExecuteDataTable(GlobalVar.dbName, Query);
foreach (DataRow Row in Types.Rows)
{
List.Add(Row["Status_Title"].ToString(), Row["Status_Info"].ToString());
}
return List;
}
public const string GlobalString = "ProjectDatabase.mdf";
public static Dictionary<string, string> LoginTypes = GenerateLoginStatus(LoginTypes);
}
Table structure:
Status_Title Status_Info
AlreadyLoggedIn User is already logged in.
A B
C D
And I use it in another page: GlobalVar.LoginStatus["AlreadyLoggedIn"]
The "AlreadyLoggedIn" is created in the database for sure, but when I call any of the keys, it returns an exception (doesn't tell which exception).
EDIT: I changed the code a bit, and it now gives "The type initializer for 'GlobalVar' threw an exception."
I suppose you might be getting null reference exception which is caused because you call your static initialization method with instance you want to initialize (LoginTypes):
public static Dictionary<string, string> LoginTypes =
GenerateLoginStatus(LoginTypes);
When GenerateLoginStatus executes, LoginTypes is null. Yet you attempt to add items to it:
static Dictionary<string, string> GenerateLoginStatus(
Dictionary<string, string> List)
{
// ...
List.Add(Row["Status_Title"].ToString(), Row["Status_Info"].ToString());
This causes null reference exception. You should use type constructor and create that dictionary there:
static GlobalVar()
{
LoginTypes = new Dictionary<string, string>();
// proceed with initialization
}

Convert IDictionary<string, string> keys to lowercase (C#)

I've got a Method that gets a IDictionary as a parameter.
Now I want to provide a method that retrieves the value from this dictionary, but it should be case-invariant.
So my solution to this right now was to have a static function that loops through the keys and converts them toLower() like this:
private static IDictionary<ILanguage, IDictionary<string, string>> ConvertKeysToLowerCase(
IDictionary<ILanguage, IDictionary<string, string>> dictionaries)
{
IDictionary<ILanguage, IDictionary<string, string>> resultingConvertedDictionaries
= new Dictionary<ILanguage, IDictionary<string, string>>();
foreach(ILanguage keyLanguage in dictionaries.Keys)
{
IDictionary<string, string> convertedDictionatry = new Dictionary<string, string>();
foreach(string key in dictionaries[keyLanguage].Keys)
{
convertedDictionatry.Add(key.ToLower(), dictionaries[keyLanguage][key]);
}
resultingConvertedDictionaries.Add(keyLanguage, convertedDictionatry);
}
return resultingConvertedDictionaries;
}
Now, this is ok, but still it's a pretty huge chunk of code that contradicts my idea of "clean and efficient". Do you know any alternatives to this so that the .ContainsKey() method of the dictionary doesn't differentiate between casing?
Yes - pass the Dictionary constructor StringComparer.OrdinalIgnoreCase (or another case-ignoring comparer, depending on your culture-sensitivity needs).
By using a StringDictionary the keys are converted to lower case at creating time.
http://simiansoftware.blogspot.com/2008/11/have-const-string-with-ui-description.html
You could use the var keyword to remove some clutter. Technically the source remains the same. Also I would just pass and return a Dictionary<string, string> because you're not doing anything with that ILanguage parameter and make the method more reusable:
private static IDictionary<string, string> ConvertKeysToLowerCase(
IDictionary<string, string> dictionaries)
{
var convertedDictionatry = new Dictionary<string, string>();
foreach(string key in dictionaries.Keys)
{
convertedDictionatry.Add(key.ToLower(), dictionaries[key]);
}
return convertedDictionatry;
}
... and call it like so:
// myLanguageDictionaries is of type IDictionary<ILanguage, IDictionary<string, string>>
foreach (var dictionary in myLanguageDictionaries.Keys)
{
myLanguageDictionaries[dictionary].Value =
ConvertKeysToLowerCase(myLanguageDictionaries[dictionary].Value);
}
You could inherit from IDictionary yourself, and simply marshal calls to an internal Dictionary instance.
Add(string key, string value) { dictionary.Add(key.ToLowerInvariant(), value) ; }
public string this[string key]
{
get { return dictionary[key.ToLowerInvariant()]; }
set { dictionary[key.ToLowerInvariant()] = value; }
}
// And so forth.
System.Collections.Specialized.StringDictionary() may help. MSDN states:
"The key is handled in a case-insensitive manner; it is translated to lowercase before it is used with the string dictionary.
In .NET Framework version 1.0, this class uses culture-sensitive string comparisons. However, in .NET Framework version 1.1 and later, this class uses CultureInfo.InvariantCulture when comparing strings. For more information about how culture affects comparisons and sorting, see Comparing and Sorting Data for a Specific Culture and Performing Culture-Insensitive String Operations."
You can also try this way
convertedDictionatry = convertedDictionatry .ToDictionary(k => k.Key.ToLower(), k => k.Value.ToLower());
LINQ version using the IEnumerable<T> extension methods:
private static IDictionary<ILanguage, IDictionary<string, string>> ConvertKeysToLowerCase(
IDictionary<ILanguage, IDictionary<string, string>> dictionaries)
{
return dictionaries.ToDictionary(
x => x.Key, v => CloneWithComparer(v.Value, StringComparer.OrdinalIgnoreCase));
}
static IDictionary<K, V> CloneWithComparer<K,V>(IDictionary<K, V> original, IEqualityComparer<K> comparer)
{
return original.ToDictionary(x => x.Key, x => x.Value, comparer);
}

Categories