I am trying to add an extension for a Dictionary who takes key-value a key and a Dictionary, as follows, but I receive error 'Cannot implicitly convert type bool to string':
public static string GetParameterValue(
this Dictionary<string, Dictionary<string, string>> src, string section, string key, out string value)
{
value = null;
if (src.TryGetValue(section, out Dictionary<string, string> sectionValue))
{
bool hasValue = sectionValue.TryGetValue(key, out value);
return hasValue; //error... how to return value here when hasValue is true?
}
return string.Empty;
}
I have multiple sections (imagine categories) and each section has a huge list of parameters and their values; section One has a list of key/value pairs, section Two the same etc.
I am trying to have a Dictionary which is of the form
Dictionary<string, Dictionary<string, string>> Sections = new Dictionary<string, Dictionary<string, string>>();
which I populate like
Sections["Italian"].Add("Good morning", "Buon giorno");
and I want to have an extension so that I can do
string myWord = Sections.GetParameterValue("Italian", "Good morning")
so that myWord is "Buon giorno".
Maybe could you help?
try this
Dictionary<string, Dictionary<string, string>> Sections = new Dictionary<string, Dictionary<string, string> >();
Sections.AddParameterValue("Italian","Good afternoon", "Buon afternoon");
Sections.AddParameterValue("Italian","Good morning", "Buon giorno");
string myWord = Sections.GetParameterValue("Italian", "Good morning");
public static class Extensions
{
public static string GetParameterValue(
this Dictionary<string, Dictionary<string, string>> src, string key1, string key2)
{
if (src.TryGetValue(key1, out var sectionValue))
if (sectionValue.TryGetValue(key2, out var result)) return result;
return string.Empty;
}
public static void AddParameterValue(
this Dictionary<string, Dictionary<string, string>> src, string section, string key, string value)
{
if (!src.TryGetValue(section, out _)) src[section] = new Dictionary<string, string>();
if (src[section].TryGetValue(key, out _)) src[section][key] = value;
else src[section].Add(key, value);
}
}
Related
I want to group by my list of dictionaries dynamically just like:
public static List<Dictionary<string, ClassName>> GroupBy(this List<Dictionary<string, ClassName>> list)
{
return list.AsQueryable().GroupBy(i => new { Key1 = i["Key01"].ClassProperty, Key2 = i["Key02"].AnotherClassProperty });
}
but I need to set keys name and numbers dynamically.
I had an idea to create dynamic-typed variable using ExpandoObject like that:
public static List<Dictionary<string, ClassName>> GroupBy(this List<Dictionary<string, ClassName>> list, IEnumerable<string> fieldnames)
{
return list.AsQueryable().GroupBy(i => GetKeys(fieldnames, dict) });
dynamic GetKeys(IEnumerable<string> fieldnames, Dictionary<string, ClassName> dict)
{
IDictionary<string, object> sampleObject = new ExpandoObject();
foreach (var fieldname in fieldnames)
{
sampleObject.Add($"Key{sampleObject.Count}", dict.GetValueOrDefault(fieldname).ClassProperty;
}
return sampleObject;
}
}
I have a use case, where I have to show any List of objects List<T> objects as a table. So, I have implemented a function, which prepares the data in usable format:
public static Dictionary<Guid, Dictionary<string, object>> PrepareList<T>(List<T> Items, List<string> RelevantProperties)
{
var res = new Dictionary<Guid, Dictionary<string, object>>();
var propDicSplitted = new Dictionary<string, List<string>>();
foreach (string relevantProperty in RelevantProperties)
{
if (relevantProperty.Contains("."))
{
var split = relevantProperty.Split('.');
if(!propDicSplitted.ContainsKey(split[0]))
{
propDicSplitted.Add(split[0], new List<string>());
}
propDicSplitted[split[0]].Add(relevantProperty);
}
}
foreach (T item in Items)
{
var itemPropDic = item.ToDictionary();
var itemId = (Guid)itemPropDic["ID"];
if (!res.ContainsKey(itemId))
{
res.Add(itemId, new Dictionary<string, object>());
}
foreach(string relevantProperty in RelevantProperties)
{
if (itemPropDic.ContainsKey(relevantProperty)) {
res[itemId].Add(relevantProperty, itemPropDic[relevantProperty]);
}
}
foreach(string subObjectName in propDicSplitted.Keys)
{
foreach (string relevantSubProperty in propDicSplitted[subObjectName])
{
res[itemId].Add(relevantSubProperty, GetNestedPropertyValue(itemPropDic, relevantSubProperty.Split('.')));
}
}
}
return res;
}
private static object GetNestedPropertyValue(IDictionary<string, object> Obj, string[] PropertiesPath)
{
if (PropertiesPath.Length == 1)
return Obj[PropertiesPath[0]];
return GetNestedPropertyValue(Obj[PropertiesPath[0]].ToDictionary(), PropertiesPath.Skip(1).ToArray());
}
where, List<T> items is the list of items to be shown in table and List<string> RelevantProperties are the property names, which are relevant for the table. These can be nested via '.' (eg. when the Orders object has a Customer object as a property and I need to show the customer name, then it will be possible to add value to RelevantProperties as "Customer.Name", which then will be extracted).
The .ToDictionary() method is extended to provide the access to the properties as in dictionary:
public static IDictionary<string, object> ToDictionary(this object source, bool ignoreComplexTypes = false)
{
return source.ToDictionary<object>(ignoreComplexTypes);
}
public static IDictionary<string, T> ToDictionary<T>(this object source, bool ignoreComplexTypes)
{
if (source == null)
throw new ArgumentNullException("source", "Unable to convert object to a dictionary. The source object is null.");
var dictionary = new Dictionary<string, T>();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
AddPropertyToDictionary<T>(property, source, dictionary, ignoreComplexTypes);
return dictionary;
}
private static void AddPropertyToDictionary<T>(PropertyDescriptor property, object source, Dictionary<string, T> dictionary, bool ignoreComplexTypes)
{
object value = property.GetValue(source);
if (IsOfType<T>(value) && !(ignoreComplexTypes))
dictionary.Add(property.Name, (T)value);
}
private static bool IsOfType<T>(object value)
{
return value is T;
}
However, the problem is that the function PrepareList<T>() is too slow and it takes 2 minutes for a list with 10000 items and 8 relevant properties. I need a hint on how to optimize this. Any suggestions are appreciated.
I'm trying to learn and practice OOP principles and I need some help with an example to get me over the hump. I have the following code:
using System.Collections.Generic;
namespace Test
{
class Program
{
static void Main()
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("cat", "one");
dictionary.Add("dog", "two");
dictionary.Add("llama", "three");
dictionary.Add("iguana", "four");
var test1 = GetKVP(dictionary, "llama");
var test2 = GetValue(dictionary, "llama");
var test3 = GetPosition(dictionary, "llama");
}
static KeyValuePair<string, string> GetKVP(Dictionary<string, string> dict, string key_to_find)
{
foreach (KeyValuePair<string, string> kvp in dict)
{
if (kvp.Key == key_to_find)
{return kvp;}
}
return new KeyValuePair<string, string>();
}
static string GetValue(Dictionary<string, string> dict, string key_to_find)
{
foreach (KeyValuePair<string, string> kvp in dict)
{
if (kvp.Key == key_to_find)
{return kvp.Value;}
}
return string.Empty;
}
static int GetPosition(Dictionary<string, string> dict, string key_to_find)
{
int counter = 0;
foreach (KeyValuePair<string, string> kvp in dict)
{
if (kvp.Key == key_to_find)
{return counter;}
counter += 1;
}
return -1;
}
}
}
What I'm trying to do is consolidate the code set so that I can have a single method which returns a different data type without duplicating code. Please don't comment on the fact that there are several more efficient ways to search a dictionary, I'm aware that this is not ideal.. I simply mocked up some data and methods to use as an example. For the life of me, I can't really visualize how to implement something like that.
You could try doing this, but I don't think it helps too much:
static R GetResult<R>(Dictionary<string, string> dict, string key_to_find, Func<KeyValuePair<string, string>, R> selector, R otherwise)
{
return dict.Where(kvp => kvp.Key == key_to_find).Select(kvp => selector(kvp)).DefaultIfEmpty(otherwise).First();
}
static KeyValuePair<string, string> GetKVP(Dictionary<string, string> dict, string key_to_find)
{
return GetResult(dict, key_to_find, kvp => kvp, new KeyValuePair<string, string>());
}
static string GetValue(Dictionary<string, string> dict, string key_to_find)
{
return GetResult(dict, key_to_find, kvp => kvp.Value, String.Empty);
}
static int GetPosition(Dictionary<string, string> dict, string key_to_find)
{
return dict.Where(kvp => kvp.Key == key_to_find).Select((kvp, n) => n).DefaultIfEmpty(-1).First();
}
In .net everthing is based on Object, so just return Object and then object could be anything just as you want
here is a sample based on your code
using System.Collections.Generic;
namespace Test
{
class Program
{
static void Main()
{
Dictionary<string, Object> dictionary = new Dictionary<string, string>();
dictionary.Add("cat", "one");
dictionary.Add("dog", "two");
dictionary.Add("llama", "three");
dictionary.Add("iguana", "four");
var test1 = GetWhatEver(dictionary, "llama");
var test2 = GetWhatEver(dictionary, "llama");
var test3 = GetWhatEver(dictionary, "llama");
}
static Object GetWhatEver(Dictionary<string, Object> dict, string key_to_find)
{
foreach (var kvp in dict)
{
if (kvp.Key == key_to_find)
{return kvp.Value;}
}
return null;
}
}
}
I have a static class to hold a dictionary and 2 get methods to access it
Here is my class:
public static class ConfiguraCuadros
{
public static Dictionary<string,Dictionary<string,Dictionary<string,Dictionary<string,string>>>> GetDictionary()
{
// Try to get the result in the static Dictionary
return _configcuadros;
}
public static Dictionary<string, Dictionary<string, Dictionary<string, string>>> GetHoja(string key)
{
// Try to get the result in the static Dictionary
Dictionary<string, Dictionary<string, Dictionary<string, string>>> result = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
if (_configcuadros.TryGetValue(key, out result))
{
return result;
}
else
{
return null;
}
}
public static readonly Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> _configcuadros = new Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>
{
{ "Formato01", //this is just a hint, the dictionary is much more extensive
new Dictionary<string, Dictionary<string, Dictionary<string, string>>>
{
{
"F01C01A",
new Dictionary<string, Dictionary<string, string>>
{
{
"X",
new Dictionary<string, string>
{
{ "key1" , "value1" },
{ "key2" , "value2" },
{ "key3" , "value3" },
}
},
}
},
}
},
}
}`
When I use the getter method,
ConfiguraCuadros.GetDictionary();
It throws an exception:
A first chance exception of type 'System.ArgumentException' occurred in mscorlib.dll
'ConfiguraCuadros.GetDictionary()' threw an exception of type 'System.TypeInitializationException'
base: {"The type initializer for 'beDGRAIC.ConfiguraCuadros' threw an exception."}
TypeName: "beDGRAIC.ConfiguraCuadros"
or
'ConfiguraCuadros.GetHoja("Formato01")' threw an exception of type 'System.TypeInitializationException'
base: {"The type initializer for 'beDGRAIC.ConfiguraCuadros' threw an exception."}
TypeName: "beDGRAIC.ConfiguraCuadros"
As you can see, my intention is to have a static dictionary. I think the problem is in the dictionary declaration ... but I can't see where...
Just in case, "beDGRAIC" is my namespace.
Thanks for your help!
Your code works (almost) as is for me.
I just added a missing semi-colon to get it to compile but can then call ConfiguraCuadros.GetDictionary(); without any exception.
Here is the code back with that missing semicolon:
public static class ConfiguraCuadros
{
public static Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> GetDictionary()
{
// Try to get the result in the static Dictionary
return _configcuadros;
}
public static Dictionary<string, Dictionary<string, Dictionary<string, string>>> GetHoja(string key)
{
// Try to get the result in the static Dictionary
Dictionary<string, Dictionary<string, Dictionary<string, string>>> result = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
if (_configcuadros.TryGetValue(key, out result))
{
return result;
}
else
{
return null;
}
}
public static readonly Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> _configcuadros = new Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>
{
{ "Formato01", //this is just a hint, the dictionary is much more extensive
new Dictionary<string, Dictionary<string, Dictionary<string, string>>>
{
{
"F01C01A",
new Dictionary<string, Dictionary<string, string>>
{
{
"X",
new Dictionary<string, string>
{
{ "key1" , "value1" },
{ "key2" , "value2" },
{ "key3" , "value3" },
}
},
}
}
}
}
};
}
[UPDATE]
I do agree with the comments above about checking out the InnerException as a general rule for a type initialisation exception and, particularly, about the unfriendly nature of the datatype!
Trying to copy values from an existing NameValueCollection object to a Dictionary. I have the following code below to do that but seems the Add does not accept that my keys and values are as Strings
IDictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>();
public void copyFromNameValueCollection (NameValueCollection a)
{
foreach (var k in a.AllKeys)
{
dict.Add(k, a[k]);
}
}
Note: NameValueCollection contains String keys and values and so I simply want to provide here a method to allow copying of those to a generic dictionary.
Extension method plus linq:
public static Dictionary<string, string> ToDictionary(this NameValueCollection nvc) {
return nvc.AllKeys.ToDictionary(k => k, k => nvc[k]);
}
//example
var dictionary = nvc.ToDictionary();
It doesn't make sense to use generics here since you can't assign strings to some arbitrary generic type:
IDictionary<string, string> dict = new Dictionary<string, string>();
public void copyFrom(NameValueCollection a)
{
foreach (var k in a.AllKeys)
{
dict.Add(k, a[k]);
}
}
although you should probably create a method to create a new dictionary instead:
public static IDictionary<string, string> ToDictionary(this NameValueCollection col)
{
IDictionary<string, string> dict = new Dictionary<string, string>();
foreach (var k in col.AllKeys)
{
dict.Add(k, col[k]);
}
return dict;
}
which you can use like:
NameValueCollection nvc = //
var dictionary = nvc.ToDictionary();
If you want a general way of converting the strings in the collection into the required key/value types, you can use type converters:
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this NameValueCollection col)
{
var dict = new Dictionary<TKey, TValue>();
var keyConverter = TypeDescriptor.GetConverter(typeof(TKey));
var valueConverter = TypeDescriptor.GetConverter(typeof(TValue));
foreach(string name in col)
{
TKey key = (TKey)keyConverter.ConvertFromString(name);
TValue value = (TValue)valueConverter.ConvertFromString(col[name]);
dict.Add(key, value);
}
return dict;
}
parameters.AllKeys.ToDictionary(t => t, t => parameters[t]);
Use LINQ:
public static IDictionary<string, string> ToDictionary(this NameValueCollection collection)
{
return collection.Cast<string>().ToDictionary(k => k, v => collection[v]);
}
Usage:
IDictionary<string, string> dic = nv.ToDictionary();
Super-Short Version
var dataNvc = HttpUtility.ParseQueryString(data);
var dataCollection = dataNvc.AllKeys.ToDictionary(o => o, o => dataNvc[o]);
If you know that your dictionary is always going to contain strings, specify it to contain strings instead of making your class generic:
IDictionary<string, string> dict = new Dictionary<string, string>();
With this, things will "just work" as written (without the generic method specification).
If you need this to be a generic class, and hold generic data, you need some way to convert from string to TKey and string to TValue. You could provide delegates to your copy method to do this:
public void CopyFrom(NameValueCollection a, Func<string, TKey> keyConvert, Func<string, TValue> valueConvert)
{
foreach(var k in a.AllKeys)
{
dict.Add(keyConvert(k), valueConvert(a[k]));
}
}
You would then need to pass a delegate in that would perform the conversion from string to TValue and string to TKey.
You should not forget about EqualityComparer. But it is not a public property. So, you should use reflection to get it.
public static IEqualityComparer GetEqualityComparer(this NameObjectCollectionBase nameObjectCollection)
{
PropertyInfo propertyInfo = typeof(NameObjectCollectionBase).GetProperty("Comparer", BindingFlags.Instance | BindingFlags.NonPublic);
return (IEqualityComparer)propertyInfo.GetValue(nameObjectCollection);
}
public static IEqualityComparer<string> GetEqualityComparer(this NameValueCollection nameValueCollection)
{
return (IEqualityComparer<string>)((NameObjectCollectionBase)nameValueCollection).GetEqualityComparer();
}
public static Dictionary<string, string> ToDictionary(this NameValueCollection nameValueCollection)
{
Dictionary<string, string> dictionary =
nameValueCollection.AllKeys.ToDictionary(x => x, x => nameValueCollection[x], nameValueCollection.GetEqualityComparer());
return dictionary;
}