Missing changes in Dictionary - c#

I am working on a WFP application which contains a dynamic grid depending on the order type in question. Therefore I have bound the grid to a Dictionary<string, object>.
However on one screen where I allow users to paste in new orders, I noticed that sometimes not all values are persisted, typically when they paste in a large number, say 500 rows. I suspect this is because I am using Dictionary rather than ConcurrentDictionary so not all writes to the Dictionary are being persisted.
Order Object:
public interface IOrder : IDictionary<string, object>,
{
IOrderDataDictionary<string, object> OrderData { get; set; }
}
OrderDataDictionary
public class OrderDataDictionary<TKey, TValue> : IOrderDataDictionary<TKey, TValue>
{
private static readonly ILog Log = LogManager.GetLogger(typeof(OrderDataDictionary<TKey, TValue>));
private readonly IDictionary<TKey, TValue> _innerDictionary;
#region Constructors
public OrderDataDictionary()
{
_innerDictionary = new Dictionary<TKey, TValue>();
}
public OrderDataDictionary(int capacity)
{
_innerDictionary = new Dictionary<TKey, TValue>(capacity);
}
public OrderDataDictionary(IDictionary<TKey, TValue> dictionary)
{
_innerDictionary = new Dictionary<TKey, TValue>(dictionary);
}
...
}
Adding to Dictionary:
public Order ParseRows(List<string> rawRow, OrderType orderType)
{
Order order = GenerateOrderEntryRow(orderType);
List<string> row = rawRow.Select(x => x.ToString()).ToList();
foreach (BulkEntryColumnConfig column in _pasteHeader[orderType])
{
if (!column.IncludeInRequest || !column.AutoParse)
continue;
string rawVal = row[column.Index];
if (column.DataType == typeof (string))
{
Log.DebugFormat("{0}:{1}", column.Name, rawVal);
order.OrderData[column.Name] = rawVal;
}
}
...
return order;
}
Order
public Order()
{
_innerDictionary = new OrderDataDictionary<string, object>();
OrderData = _innerDictionary;
}
public Order(IDictionary<string, object> dictionary)
{
_innerDictionary = new OrderDataDictionary<string, object>(dictionary);
OrderData = _innerDictionary;
}
GenerateOrderEntryRow()
public Order GenerateOrderRow(OrderType orderType)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
foreach (KeyValuePair<string, string> col in _columnDefinition[orderType])
{
dict.Add(col.Key, null);
}
dict["OrderType"] = orderType.ToString();
Order row = new Order(dict);
return row;
}
Calling ParseRows()
return Task<IList<Order>>.Factory.StartNew(() => {...ParseRows()...}
The key line is order.OrderData[column.Name] = rawVal; where I am adding a value to the dictionary using the indexer.
I'm never calling Order() which would mean a potential resizing of the underlying dictionary later. I only call Order(IDictionary dictionary) from GenerateOrderEntryRow() so not unless it is being invoked somewhere else implicitly.
My question is, why are not all values stored correctly, and should I modify Order.OrderData to be of type ConcurrentDictionary? Would this solve the problem of some writes being missed?

Related

Make Dictionary<Type, Dictionary<string, object>> strongly-typed

In my application users can search for different things in various places. The same search code could be used for different things. I'm trying to create a cache in order to avoid querying the database every time.
// CustomerViewModel.cs
public async Task<Customer> SearchCustomerAsync(string searchCode)
{
if (Cache.GetOrDefault<Customer>(searchCode) is Customer c)
{
return c;
}
var customer = await GetCustomerFromDatabaseAsync(searchCode);
Cache.AddOrReplace(searchCode, customer);
return customer;
}
// SupplierViewModel.cs
public async Task<Supplier> SearchSupplierAsync(string searchCode)
{
if (Cache.GetOrDefault<Supplier>(searchCode) is Supplier s)
{
return s;
}
var supplier = await GetSupplierFromDatabaseAsync(searchCode);
Cache.AddOrReplace(searchCode, supplier);
return supplier;
}
Here is my cache implementation
public static class Cache
{
private static readonly Dictionary<Type, Dictionary<string, object>> _dictionary =
new Dictionary<Type, Dictionary<string, object>>();
public static void AddOrReplace<T>(string key, T value) where T : class
{
Type t = typeof(T);
if (!_dictionary.ContainsKey(t)) _dictionary.Add(t, new Dictionary<string, object>());
var cache = _dictionary[t];
if (cache.ContainsKey(key)) cache.Remove(key);
cache.Add(key, value);
}
public static T GetOrDefault<T>(string key) where T : class
{
Type t = typeof(T);
if (!_dictionary.ContainsKey(t)) return default;
var cache = _dictionary[t];
if (!cache.ContainsKey(key)) return default;
// Have to explicitly cast the object to T
return (T)cache[key];
}
}
The thing that bothers me is the inner dictionary being Dictionary<string, object>. For a given type, say Customer, I know that the inner dictionary will only ever contains customers, and should be Dictionary<string, Customer>.
Is there a way to have the inner dictionary strongly typed?
If not, would a Dictionary<string, Dictionary<Type, object>> be better suited? So I would check whether or not I've got something cached for the search code, and if so something cached for the given type.
I'm open to all suggestions, so if you think my approach is bad and I shouldn't even use a dictionary in the first place I'm all ears.
UPDATE:
As pointed out, given I'm only caching reference types I shouldn't be too worried about dealing with objects, since I won't be boxing value types. I've replaced the nested dictionaries with a Dictionary<(string, Type), object>.
public static class Cache
{
private static readonly Dictionary<(string, Type), object> _dictionary =
new Dictionary<(string, Type), object>();
public static void AddOrReplace<T>(string key, T value) where T : class
{
var typedKey = (key, typeof(T));
if (_dictionary.ContainsKey(typedKey)) _dictionary.Remove(typedKey);
_dictionary.Add(typedKey, value);
}
public static T GetOrDefault<T>(string key) where T : class
{
var typedKey = (key, typeof(T));
if (!_dictionary.TryGetValue(typedKey, out object value)) return default;
return (T)value;
}
}

Converting object to Dictionary<PropertyName, Value>

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.

getters and setters with dictionary in c#

I have following parent class:
public class BaseType
{
public abstract Dictionary<string, object> dict { get; set; }
}
Child class:
public override Dictionary<string, object> dict
{
get
{
return fn();
}
set
{
//set dictionary[key]=value }
}
fn is implemented in child class as:
public static Dictionary<string, object> fn()
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
dictionary.Add("key1", "0");
dictionary.Add("key2", "something");
return dictionary;
}
I need to access this dictionary as follows:
BaseType test=new Child();
test.dict["key1"]=1;//set property
object strGet= test.dict["key2];//get property
How can I achieve the above get and set?
Your parent class is already invalid. You cannot have a property that takes arguments.
You can only expose the dictionary as a property itself. Note that you also need to make the class abstract as well:
public abstract class BaseType
{
public abstract Dictionary<string, object> Dict { get; set; }
}
Then, in subtypes of that class, you can set up the getter and setter so it returns a custom dictionary:
public class MyType : BaseType
{
public override Dictionary<string, object> Dict
{
get
{
return GetSomeDictionary();
}
set
{
DoSomethingWith(value);
}
}
}
Note, that this does not allow you to overwrite the behavior when you do someObj.Dict["key"] = "foo". The item accessor is built into the dictionary type, and you cannot overwrite that from within your class.
What you could do is expose a IDictionary<string, object> instead and provide your own type that wraps a normal dictionary but exposes your desired behavior instead.
If the whole purpose of your code is just to provide some default value for the dictionary, then you can solve this a lot easier:
public class MyType : BaseType
{
private Dictionary<string, object> _dict = null;
public override Dictionary<string, object> Dict
{
get
{
if (_dict == null)
{
_dict = InitializeDictionary();
}
return _dict;
}
set
{
_dict = value;
}
}
}
Where InitializeDictionary() returns a new dictionary with the default values.
I got it!! This way we can dynamically set the value of any key in dictionary.
public object objValue;
public string strKey;
public override Dictionary<string, object> dictionary
{
get
{
return fn();
}
set
{
setTest(strKey,objValue);
}
}
public void setTest(string strKey, object objValue)
{
dictionary[strKey] = objValue;
}

Copy key values from NameValueCollection to Generic Dictionary

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

Two-value dictionary which returns any of the value for a specific key

I need to create a dictionary that has 2 values per key, and it must return one of the 2 values with the same probability.
Example:
myDicry
{
key = "A", value1=15, value2=56;
}
int firstCall = myDicry["A"]; // = 15
int secondCall = myDicry["A"]; // = 56
It would be possible to write an IDictionary<TKey, TValue> implementation that behaved in this manner, but that would not be a good idea: most people would find a non-deterministic indexer for a collection-class very unintuitive.
Instead, I suggest you make this the responsibility of the value for a key, rather than the Dictionary itself. One option would be to write a custom-type that is capable of picking from a set of possibilities with equal probability. For example:
public class UnbiasedRandomPicker<T>
{
private readonly Random _rand = new Random();
private readonly T[] _possibilities;
public UnbiasedRandomPicker(params T[] possibilities)
{
// argument validation omitted
_possibilities = possibilities;
}
public T GetRandomValue()
{
return _possibilities[_rand.Next(_possibilities.Length)];
}
}
You could then use the dictionary like this:
var dict = new Dictionary<string, UnbiasedRandomPicker<int>>
{
{"A", new UnbiasedRandomPicker<int>(15, 56)},
{"B", new UnbiasedRandomPicker<int>(25, 13)}
};
int randomValueFromA = dict["A"].GetRandomValue();
There's nothing built into the framework to do this, but you'd probably want to implement it by creating a "wrapper" type which had a Dictionary<TKey, Tuple<TValue, TValue>>. You'd then write an indexer to choose appropriately between the two values.
I would actually just implement this in a class that uses a Dictionary<TKey, TValue[]> internally. That way you could even implement the type to have a variable number of values per key.
Like:
class RandomDictionary<TKey, TValue>
{
Dictionary<TKey, TValue[]> m_dict;
Random m_random;
public RandomDictionary()
{
m_dict = new Dictionary<TKey, TValue[]>();
m_random = new Random();
}
public TValue this[TKey key]
{
get
{
TValue[] values = m_dict[key];
return values[m_random.Next(0, values.Length)];
}
}
public void Define(TKey key, params TValue[] values)
{
m_dict[key] = new TValue[values.Length];
Array.Copy(values, m_dict[key], values.Length);
}
public bool TryGetValue(TKey key, out TValue value)
{
TValue[] values;
if (!m_dict.TryGetValue(key, out values))
{
value = default(TValue);
return false;
}
value = values[m_random.Next(0, values.Length)];
return true;
}
}
Use Tuple as dictionary value type.
IDictionary<string, Tuple<int, int>> doubleDictionary = new Dictionary<string, Tuple<int, int>>();
// ...
int secondValue = doubleDictionary["A"].Item2;
You could also write an extension method for the dictionary, so you could create something like this:
IDictionary<string, Tuple<int, int>> doubleDictionary = new Dictionary<string, Tuple<int, int>>();
doubleDictionary.GetRandomValueForKey("A");
Then you can use this with any dictionary.
public static void GetRandomValueForKey(this Dictionary<string, Tuple<int, int>> dict,
string key)
{
... Code to return the value
}
^^ that was written off the top of my head, so please excuse me if this is slightly wrong.
This below code will solve the dictionary part of the problem and make the randomization customizable so that you can apply a level so pseudo-randomness that suits your needs. (or simply hard code it instead of the use of a functor)
public class DoubleDictionary<K, T> : IEnumerable<KeyValuePair<K, T>>
{
private readonly Dictionary<K, Tuple<T, T>> _dictionary = new Dictionary<K, Tuple<T, T>>();
private readonly Func<bool> _getFirst;
public DoubleDictionary(Func<bool> GetFirst) {
_getFirst = GetFirst;
}
public void Add(K Key, Tuple<T, T> Value) {
_dictionary.Add(Key, Value);
}
public T this[K index] {
get {
Tuple<T, T> pair = _dictionary[index];
return GetValue(pair);
}
}
private T GetValue(Tuple<T, T> Pair) {
return _getFirst() ? Pair.Item1 : Pair.Item2;
}
public IEnumerable<K> Keys {
get {
return _dictionary.Keys;
}
}
public IEnumerable<T> Values {
get {
foreach (var pair in _dictionary.Values) {
yield return GetValue(pair);
}
}
}
IEnumerator<KeyValuePair<K, T>> IEnumerable<KeyValuePair<K, T>>.GetEnumerator() {
foreach (var pair in _dictionary) {
yield return new KeyValuePair<K, T>(pair.Key, GetValue(pair.Value));
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return ((IEnumerable<KeyValuePair<K, T>>)this).GetEnumerator();
}
}

Categories

Resources