List of dictionaries vs nested dictionaries - c#

To explain a little my environment, I need to keep track of users and a collection of things each user own. This is highly dynamic, although the number of base users is always higher than the collection of things they own. I decided to go with something like this:
private static Dictionary<string, Dictionary<string, MyClass>> ActiveUsers =
new Dictionary<string, Dictionary<string, MyClass>>();
In this case, the TKey for the parent Dictionary is the connectionId of an user, and the TKey for the inner dictionary is a string that represents the Id of MyClass
What I meant before is that ActiveUsers will hold (hopefully) a great number of TKeys, while the TValues will normally hold less than 10 items. As these items are related, when a user disconnects, it is deleted from the parent Dictionary, and all other items in the parent Dictionary will be searched for some value in their inner dictionary and these will be deleted if present.
This field will be accessed constantly (extremely often) and I'm trying to achieve the best performance possible.
Is this a better approach (performance-related) than creating a class with an ID and Dictionary<string, MyClass> as fields and holding a list of this class?
Would something like this be better?
public class ActiveUsersManager
{
public string Id{ get; private set; }
public Dictionary<string, MyClass> ActiveUsers { get; private set; }
public ActiveUsersManager(string connectionId)
{
Id = connectionId;
ActiveUsers = new Dictionary<string, MyClass>();
}
}
//In another class
private static List<ActiveUsersManager> ActiveUsers = new List<ActiveUsersManager>();
If it helps, the ActiveUsers is a static field in an ASP.NET Controller.
EDIT: answering comments
This dictionary is consumed as this:
public static MyClass GetInformation(string myId, string objectId)
{
//Validation removed
Dictionary<string, MyClass> dictionaryResult = null;
MyClass result = null;
if (!ActiveUsers.TryGetValue(myId, out dictionaryResult)) //check if the user was already added to the Dictionary
{
dictionaryResult = new Dictionary<string, MyClass>();
result = new MyClass(objectId);
dictionaryResult.Add(objectId, result);
ActiveUsers.Add(myId, dictionaryResult);
}
else if (!dictionaryResult.TryGetValue(objectId, out result)) //otherwise check if the user already has this item
{
result = new MyClass(objectId);
dictionaryResult.Add(objectId, result);
ActiveUsers.Add(myId, dictionaryResult);
}
//else everything is already set-up
return result;
}
EDIT: Code that shows how the inner items are deleted
public static void RemoveUserAndSessions(string userId, string objectId)
{
ActiveUsers.Remove(userId);
foreach (Dictionary<string, MyClass> dic in ActiveUsers.Values)
dic.Remove(objectId);
}
This is the first ASP.NET application I work in, and I haven't done any multithreading that involved dictionaries before, how could I make this thread-safe?
EDIT: trying to make things more clear.
I didn't want to reveal details, but I guess they are needed to understand the reason behind this. This is for a chat application. Each user is stored in ActiveUsers to keep track of, well, active users. Each user has a Dictionary of the clients they are connected with, and the MyClass object contains a set of properties needed for the client to communicate. As soon as a user disconnects, all the active sessions must be immediately deleted, hence the delete method. I imagine this could be done by creating another class to hold active sessions in a Dictionary and have this class in the original Dictionary.
As suggested, I'll take a look at the ConcurrentDictionary

I strongly advise structuring the data more like this:
private static ConcurrentDictionary<string, ActiveUser> ActiveUsers { get; set; }
private class ActiveUser {
public int ConnectionId { get; set; }
public Dictionary<string, MyClass> MyClasses { get; set; } = new Dictionary<string, MyClass>();
}
// . . .
Dictionary<string, ActiveUser> ActiveUsers = new Dictionary<string, ActiveUser>();
(Note: If you are using C# < 6, just initialize the dictionary in the ActiveUser constructor)
And for your delete method, you may want to do something such as:
public static void RemoveUserAndSessions(string userId, string objectId)
{
ActiveUsers.Remove(userId);
Parallel.ForEach(ActiveUsers.Values, dic => dic.Remove(objectId));
}
Edit: Renamed some things for clarity.

The main problem from performance perspective I see in your design is the need to iterate all the dictionaries during the RemoveUserAndSessions method. Here is a sample design that does not have that problem
static class UserManager
{
private static readonly Dictionary<string, User> ActiveUsers = new Dictionary<string, User>();
public static User GetInformation(string userId)
{
lock (ActiveUsers)
{
User user;
if (!ActiveUsers.TryGetValue(userId, out user))
ActiveUsers.Add(userId, user = new User(userId));
return user;
}
}
public static void RemoveUserAndSessions(string userId)
{
lock (ActiveUsers)
{
User user;
if (ActiveUsers.TryGetValue(userId, out user))
{
ActiveUsers.Remove(userId);
user.EndAllSessions();
}
}
}
public static void StartSession(string firstUserId, string secondUserId)
{
lock (ActiveUsers)
{
var firstUser = GetInformation(firstUserId);
var secondUser = GetInformation(secondUserId);
firstUser.StartSession(secondUser);
secondUser.StartSession(firstUser);
}
}
}
class User
{
private Dictionary<string, User> sessions = new Dictionary<string, User>();
public string Id { get; private set; }
public User(string id) { Id = id; }
public void StartSession(User other)
{
sessions.Add(other.Id, other);
}
public void EndSession(User other)
{
sessions.Remove(other.Id);
}
public void EndAllSessions()
{
foreach (var other in sessions.Values)
other.EndSession(this);
sessions.Clear();
}
}
This is just to get the idea, hope you can map it to your concrete case.

Related

Signal and Wait in C#

In the below application there are two parties that are calling ChannelReservationCache to fetch or add information.
I want to use the "signal and wait" thing in my ChannelReservationCache class so that in case ChannelReservationCache.AddChannelState() is adding the cache, parallelly if the WebApi call hits the ChannelReservationCache.GetChannel() then the GetChannel() should wait for the execution of AddChannelState() and vice-versa.
How this can be done in ChannelReservationCache class?
Will there be any deadlock?
public class ChannelReservationCache
{
private readonly IDictionary<int, string> channelStates = new Dictionary<int, string>>();
private readonly object lockObject = new object();
private static readonly object lock = new object();
private static ChannelReservationCache instance = null;
private ChannelReservationCache() {}
public static ChannelReservationCache Instance
{
get
{
lock(lock) {
if (instance == null) {
instance = new ChannelReservationCache();
}
return instance;
}
}
}
public void AddChannelState(int level, string channel)
{
lock (this.lockObject)
{
//other code that makes the function take long time.
this.AddChannel(level, channel);
}
}
public Channel GetChannel(int level)
{
//other code that makes the function take long time.
Channel c = new Channel()
channelStates.TryGetValue(destinationId, out var c);
return c;
}
private void AddChannel(int level, string channel)
{
Channel c = new Channel();
c.ChannelName = channel;
c.IsActive = true;
channelStates.Add(level, resourceState)
}
}
public class Channel
{
public string ChannelName {get; set;}
public bool IsActive {get; set;}
}
public class RMQRequestHandler
{
public Task HandleChannelRequest(int level, Channel messages)
{
ChannelReservationCache.Instance.AddChannelState(level, messages)
}
}
[Route("api/v1")]
public class ChannnelController: ControllerBase
{
[HttpGet]
[Route("ChannelResource")]
public IActionResult GetChannelResource([FromQuery] int id)
{
ChannelReservationCache crc = ChannelReservationCache.Instance.GetChannel(id);
return this.Ok(crc);
}
}
First off there is a far simpler solution for you:
Simply change
private readonly IDictionary<int, string> channelStates = new Dictionary<int, string>();
To:
private readonly IDictionary<int, string> channelStates = new System.Collections.Concurrent.ConcurrentDictionary<int, string>();
//using ConcurrentDictionary instead of Dictionary
And forget about the thread concurrency locking etc...
In reality it is pretty hard to beat the performance of ConcurrentDictionary by writing our own locking structures to wrap a normal Dictionary. It is possible using ReaderWriterLockSlim to lock the dictionary and Interlocked to maintain a custom implementation for its count property. But this is a micro optimization that would only pay out over millions of itterations.
Now to answer your question:
One issue here:
AddChannelState is threadsafe but GetChannel is not
Think of it this way. Your writer is using a threadsafe lock but your reader is not. GetChannel also needs a lock in it.
Suggestion
If you are Not using Lazy < T > in your singleton then it is probably best to make the following change
Code Example below where the cost of thread synchronization is avoided after it has been initialized. Bearing in mind that Lock (or Monitor.Enter / Exit) is one of the most expensive operations to perform. Sure there will be minimum locking contentions once it is initialized however the memory barrier is enforced each and every time plus the Monitor is being checked.
Following reference link is discussing Interlocked but the context of the memory barrier cost is the same:
https://learn.microsoft.com/en-us/archive/msdn-magazine/2005/october/understanding-low-lock-techniques-in-multithreaded-apps
private static ChannelReservationCache instance;
private static readonly object lockInstance = new object();
//lock (lockInstance) enforces a memory barrier plus the monitor which is a cost you do not need to bear once the instance has been initialized
public static ChannelReservationCache Instance
{
get
{
if (instance == null)
{
lock (lockInstance)
{
if (instance == null)
{
instance = new ChannelReservationCache();
}
}
}
return instance;
}
}

load static fields in class

I have a class with some static filds. When they are initialised they add themself to a Dictionary.
When the program starts a second time it tries to access the content of the Dictionary but since I haven't accessed any filds in the class (the Dictionary is in another) they can't be found.
I already understand that the static fields are initialised when I access one of them but are there any other ways to initialise them without calling any methods or fields for no other reason then nitialising them once?
----------------------
Here some code:
Resource.cs
public class Resource : InventoryItem
{
public const int IDBase = 1000000;
private Resource(int id) : base(IDBase + id) { }
public static Resource Hydrogen { get; } = new Resource(1); // H
public static Resource Helium { get; } = new Resource(2); // He
public static Resource Lithium { get; } = new Resource(3); // Li
public static Resource Beryllium { get; } = new Resource(4); // Be
public static Resource Boron { get; } = new Resource(5); // B
public static Resource Carbon { get; } = new Resource(6); // C
public static Resource Nitrogen { get; } = new Resource(7); // N
public static Resource Oxygen { get; } = new Resource(8); // O
// and all the other elements....
}
}
InventoryItem.cs
public abstract class InventoryItem
{
public int ID { get; }
private static readonly Dictionary<int, InventoryItem> idList = new Dictionary<int, InventoryItem>();
public InventoryItem(int id)
{
ID = id;
idList[id] = this;
}
public static InventoryItem GetFromID(int id)
{
return idList[id];
}
}
When I use InventoryItem.GetFromID(int id) before accessing anything from the Resource class the dictionary is empty and nothing can be found. If I access any resource before they are in the Dictionary.
As the static fields in a class are only initialized when you first use that class, you have to somehow force this initialization, e.g. by calling any static method in Resource.
Example:
in Resource, add
public static void Initialize()
{
// can be left empty; just forces the static fields to be initialized
}
and somewhere else in your project
Resource.Initialize();
Alternatively you could initialize them in a static constructor.
It's like a default constructor except it is static.
It is similar to Java's static { ... } block
public class Resource : InventoryItem
{
public const int IDBase = 1000000;
public static Resource Hydrogen { get; }
public static Resource Helium { get; }
public static Resource Lithium { get; }
// ...
private Resource(int id) : base(IDBase + id)
{
}
private static Resource()
{
Hydrogen = new Resource(1);
Helium = new Resource(2);
Lithium = new Resource(3);
// etc...
}
}
Caveat - I haven't actually tried this but I think it's likely to work.
Static fields and properties are initialized in a type constructor, regardless of how you write it, so both:
static Resource()
{
Hydrogen = new Resource(1);
}
and
Hydrogen { get; } = new Resource(1);
Are the same thing, the only difference is the initialization order, also it would allow you to call static fuctions, but in OP's case it really doesn't make a difference, that's why pamcevoy's answer won't work.
Klaus provides a valid way of doing things, and it will work, just you would need to call the Initialize method before your GetFromID, at least once, as to initialize all of the Resource class's static properties, e.g.:
Resource.Initialize();
InventoryItem.GetFromID(id);
Your last option is to do method shadowing, basically add to your Resource class the same GetFromID method with the new operator and then call GetFromID through the Resource class, e.g.
public class Resource : InventoryItem
{
public static new InventoryItem GetFromID(int id)
{
return InventoryItem.GetFromID(id);
}
}
But know that method shadowing isn't the same as overriding a method, so if you call InventoryItem.GetFromID you won't be calling Resource.GetFromID. This will eliminate the need for calling at startup a separate Initialize method in the Resource class but, it will force you to, at least once, call GetFromID through the Resource class.
Update: At the end of the day, the only way to initialize static fields/props is by accessing one thing or another in said class.

Dictionary of generic lists of controls

I'm working on a product calculator program. Inside the app, the rep sale person can search for a client ID and the app shows him what services he can offer to client and his provision for sale. The form is generated acording to data i download from database.
Right now I'm trying to store generated controls in lists. Every time a search is made, I dispose of controls and clear the lists. The thing i cant seem to get working is to store all the lists in single dictionary.
Something like this...
public class ListOfControls<T> : IListOfControls<T> where T : Control
{
private readonly List<T> _controlsList;
public ListOfControls()
{
_controlsList = new List<T>();
}
public void AddControll(T control)
{
_controlsList.Add(control);
}
public T this[int number]
{
get
{
return _controlsList[number];
}
}
public void ClearControls()
{
_controlsList.Clear();
}
public T Last()
{
return _controlsList.Last();
}
}
class DictionaryOfControlsLists
{
//will be private - public only for test
public readonly Dictionary<string, IListOfControls<Control>> _dictionaryOfLists;
public DictionaryOfControlsLists()
{
_dictionaryOfLists = new Dictionary<string, IListOfControls<Control>>();
}
//Other code....
}
Now trying to implement...
DictionaryOfControlsLists _testDict = new DictionaryOfControlsLists();
_testDict._dictionaryOfLists.Add("test", new ListOfControls<Label>());
Sadly this wont work...Any ideas? THANKS
What you need is something like this:
class DictionaryOfControlsLists
{
private readonly Dictionary<Type, IListOfControls<Control>> _dictionaryOfLists = new Dictionary<Type, IListOfControls<Control>>();
public void Add<T>(T control) where T : Control
{
if (!_dictionaryOfLists.ContainsKey(typeof(T)))
{
_dictionaryOfLists[typeof(T)] = new ListOfControls<Control>();
}
_dictionaryOfLists[typeof(T)].AddControl(control);
}
public T Get<T>(int number) where T : Control
{
if (!_dictionaryOfLists.ContainsKey(typeof(T)))
{
_dictionaryOfLists[typeof(T)] = new ListOfControls<Control>();
}
return _dictionaryOfLists[typeof(T)][number] as T;
}
}
Then you can do this:
DictionaryOfControlsLists _testDict = new DictionaryOfControlsLists();
_testDict.Add<Label>(new Label());
Label label = _testDict.Get<Label>(0);
If you need to extend this to have a string key then you need to implement a double dictionary within DictionaryOfControlsLists to handle it - something like a Dictionary<Type, Dictionary<string, IListOfControls<Control>>>.

Using JSON Patch to add values to a dictionary

Overview
I'm trying to write a web service using ASP.NET Core that allows clients to query and modify the state of a microcontroller. This microcontroller contains a number of systems that I model within my application - for instance, a PWM system, an actuator input system, etc.
The components of these systems all have particular properties that can be queried or modified using a JSON patch request. For example, the 4th PWM on the micro can be enabled using an HTTP request carrying {"op":"replace", "path":"/pwms/3/enabled", "value":true}. To support this, I'm using the AspNetCore.JsonPatch library.
My problem is that I'm trying to implement JSON Patch support for a new "CAN database" system that logically should map a definition name to a particular CAN message definition, and I'm not sure how to go about this.
Details
The diagram below models the CAN database system. A CanDatabase instance should logically contain a dictionary of the form IDictionary<string, CanMessageDefinition>.
To support creating new message definitions, my application should allow users to send JSON patch requests like this:
{
"op": "add",
"path": "/candb/my_new_definition",
"value": {
"template": ["...", "..."],
"repeatRate": "...",
"...": "...",
}
}
Here, my_new_definition would define the definition name, and the object associated with value should be deserialised to a CanMessageDefinition object. This should then be stored as a new key-value pair in the CanDatabase dictionary.
The issue is that path should specify a property path which for statically-typed objects would be...well, static (an exception to this is that it allows for referencing array elements e.g. /pwms/3 as above).
What I've tried
A. The Leeroy Jenkins approach
Forget the fact that I know it won't work - I tried the implementation below (which uses static-typing only despite the fact I need to support dynamic JSON Patch paths) just to see what happens.
Implementation
internal sealed class CanDatabaseModel : DeviceComponentModel<CanDatabaseModel>
{
public CanDatabaseModel()
{
this.Definitions = new Dictionary<string, CanMessageDefinition>();
}
[JsonProperty(PropertyName = "candb")]
public IDictionary<string, CanMessageDefinition> Definitions { get; }
...
}
Test
{
"op": "add",
"path": "/candb/foo",
"value": {
"messageId": 171,
"template": [17, 34],
"repeatRate": 100,
"canPort": 0
}
}
Outcome
An InvalidCastException is thrown at the site where I try to apply the specified changes to the JsonPatchDocument.
Site:
var currentModelSnapshot = this.currentModelFilter(this.currentModel.Copy());
var snapshotWithChangesApplied = currentModelSnapshot.Copy();
diffDocument.ApplyTo(snapshotWithChangesApplied);
Exception:
Unable to cast object of type 'Newtonsoft.Json.Serialization.JsonDictionaryContract' to type 'Newtonsoft.Json.Serialization.JsonObjectContract'.
B. Relying on dynamic JSON Patching
A more promising plan of attack seemed to be relying on dynamic JSON patching, which involves performing patch operations on instances of ExpandoObject. This allows you to use JSON patch documents to add, remove or replace properties since you're dealing with a dynamically-typed object.
Implementation
internal sealed class CanDatabaseModel : DeviceComponentModel<CanDatabaseModel>
{
public CanDatabaseModel()
{
this.Definitions = new ExpandoObject();
}
[JsonProperty(PropertyName = "candb")]
public IDictionary<string, object> Definitions { get; }
...
}
Test
{
"op": "add",
"path": "/candb/foo",
"value": {
"messageId": 171,
"template": [17, 34],
"repeatRate": 100,
"canPort": 0
}
}
Outcome
Making this change allows this part of my test to run without exceptions being raised, but JSON Patch has no knowledge of what to deserialise value as, resulting in the data being stored in the dictionary as a JObject rather than a CanMessageDefinition:
Would it be possible to 'tell' JSON Patch how to deserialise the information by any chance? Perhaps something along the lines of using a JsonConverter attribute on Definitions?
[JsonProperty(PropertyName = "candb")]
[JsonConverter(...)]
public IDictionary<string, object> Definitions { get; }
Summary
I need to support JSON patch requests that add values to a dictionary
I've tried going down the purely-static route, which failed
I've tried using dynamic JSON patching
This partly worked, but my data was stored as a JObject type instead of the intended type
Is there an attribute (or some other technique) I can apply to my property to let it deserialise to the correct type (not an anonymous type)?
Since there doesn't seem to be any official way to do it, I've come up with a Temporary Solution™ (read: a solution that works well enough so I'll probably keep it forever).
In order to make it seem like JSON Patch handles dictionary-like operations, I created a class called DynamicDeserialisationStore which inherits from DynamicObject and makes use of JSON Patch's support for dynamic objects.
More specifically, this class overrides methods like TrySetMember, TrySetIndex, TryGetMember, etc. to essentially act like a dictionary, except that it delegates all these operations to callbacks provided to its constructor.
Implementation
The code below provides the implementation of DynamicDeserialisationStore. It implements IDictionary<string, object> (which is the signature JSON Patch requires to work with dynamic objects) but I only implement the bare minimum of the methods I require.
The problem with JSON Patch's support for dynamic objects is that it will set properties to JObject instances i.e. it won't automatically perform deserialisation like it would when setting static properties, as it can't infer the type. DynamicDeserialisationStore is parameterised on the type of object that it will try to automatically try to deserialise these JObject instances to when they're set.
The class accepts callbacks to handle basic dictionary operations instead of maintaining an internal dictionary itself, because in my "real" system model code I don't actually use a dictionary (for various reasons) - I just make it appear that way to clients.
internal sealed class DynamicDeserialisationStore<T> : DynamicObject, IDictionary<string, object> where T : class
{
private readonly Action<string, T> storeValue;
private readonly Func<string, bool> removeValue;
private readonly Func<string, T> retrieveValue;
private readonly Func<IEnumerable<string>> retrieveKeys;
public DynamicDeserialisationStore(
Action<string, T> storeValue,
Func<string, bool> removeValue,
Func<string, T> retrieveValue,
Func<IEnumerable<string>> retrieveKeys)
{
this.storeValue = storeValue;
this.removeValue = removeValue;
this.retrieveValue = retrieveValue;
this.retrieveKeys = retrieveKeys;
}
public int Count
{
get
{
return this.retrieveKeys().Count();
}
}
private IReadOnlyDictionary<string, T> AsDict
{
get
{
return (from key in this.retrieveKeys()
let value = this.retrieveValue(key)
select new { key, value })
.ToDictionary(it => it.key, it => it.value);
}
}
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{
if (indexes.Length == 1 && indexes[0] is string && value is JObject)
{
return this.TryUpdateValue(indexes[0] as string, value);
}
return base.TrySetIndex(binder, indexes, value);
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
if (indexes.Length == 1 && indexes[0] is string)
{
try
{
result = this.retrieveValue(indexes[0] as string);
return true;
}
catch (KeyNotFoundException)
{
// Pass through.
}
}
return base.TryGetIndex(binder, indexes, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
return this.TryUpdateValue(binder.Name, value);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
try
{
result = this.retrieveValue(binder.Name);
return true;
}
catch (KeyNotFoundException)
{
return base.TryGetMember(binder, out result);
}
}
private bool TryUpdateValue(string name, object value)
{
JObject jObject = value as JObject;
T tObject = value as T;
if (jObject != null)
{
this.storeValue(name, jObject.ToObject<T>());
return true;
}
else if (tObject != null)
{
this.storeValue(name, tObject);
return true;
}
return false;
}
object IDictionary<string, object>.this[string key]
{
get
{
return this.retrieveValue(key);
}
set
{
this.TryUpdateValue(key, value);
}
}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
return this.AsDict.ToDictionary(it => it.Key, it => it.Value as object).GetEnumerator();
}
public void Add(string key, object value)
{
this.TryUpdateValue(key, value);
}
public bool Remove(string key)
{
return this.removeValue(key);
}
#region Unused methods
bool ICollection<KeyValuePair<string, object>>.IsReadOnly
{
get
{
throw new NotImplementedException();
}
}
ICollection<string> IDictionary<string, object>.Keys
{
get
{
throw new NotImplementedException();
}
}
ICollection<object> IDictionary<string, object>.Values
{
get
{
throw new NotImplementedException();
}
}
void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
}
void ICollection<KeyValuePair<string, object>>.Clear()
{
throw new NotImplementedException();
}
bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
}
bool IDictionary<string, object>.ContainsKey(string key)
{
throw new NotImplementedException();
}
void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
}
bool IDictionary<string, object>.TryGetValue(string key, out object value)
{
throw new NotImplementedException();
}
#endregion
}
Tests
The tests for this class are provided below. I create a mock system model (see image) and perform various JSON Patch operations on it.
Here's the code:
public class DynamicDeserialisationStoreTests
{
private readonly FooSystemModel fooSystem;
public DynamicDeserialisationStoreTests()
{
this.fooSystem = new FooSystemModel();
}
[Fact]
public void Store_Should_Handle_Adding_Keyed_Model()
{
// GIVEN the foo system currently contains no foos.
this.fooSystem.Foos.ShouldBeEmpty();
// GIVEN a patch document to store a foo called "test".
var request = "{\"op\":\"add\",\"path\":\"/foos/test\",\"value\":{\"number\":3,\"bazzed\":true}}";
var operation = JsonConvert.DeserializeObject<Operation<FooSystemModel>>(request);
var patchDocument = new JsonPatchDocument<FooSystemModel>(
new[] { operation }.ToList(),
new CamelCasePropertyNamesContractResolver());
// WHEN we apply this patch document to the foo system model.
patchDocument.ApplyTo(this.fooSystem);
// THEN the system model should now contain a new foo called "test" with the expected properties.
this.fooSystem.Foos.ShouldHaveSingleItem();
FooModel foo = this.fooSystem.Foos["test"] as FooModel;
foo.Number.ShouldBe(3);
foo.IsBazzed.ShouldBeTrue();
}
[Fact]
public void Store_Should_Handle_Removing_Keyed_Model()
{
// GIVEN the foo system currently contains a foo.
var testFoo = new FooModel { Number = 3, IsBazzed = true };
this.fooSystem.Foos["test"] = testFoo;
// GIVEN a patch document to remove a foo called "test".
var request = "{\"op\":\"remove\",\"path\":\"/foos/test\"}";
var operation = JsonConvert.DeserializeObject<Operation<FooSystemModel>>(request);
var patchDocument = new JsonPatchDocument<FooSystemModel>(
new[] { operation }.ToList(),
new CamelCasePropertyNamesContractResolver());
// WHEN we apply this patch document to the foo system model.
patchDocument.ApplyTo(this.fooSystem);
// THEN the system model should be empty.
this.fooSystem.Foos.ShouldBeEmpty();
}
[Fact]
public void Store_Should_Handle_Modifying_Keyed_Model()
{
// GIVEN the foo system currently contains a foo.
var originalFoo = new FooModel { Number = 3, IsBazzed = true };
this.fooSystem.Foos["test"] = originalFoo;
// GIVEN a patch document to modify a foo called "test".
var request = "{\"op\":\"replace\",\"path\":\"/foos/test\", \"value\":{\"number\":6,\"bazzed\":false}}";
var operation = JsonConvert.DeserializeObject<Operation<FooSystemModel>>(request);
var patchDocument = new JsonPatchDocument<FooSystemModel>(
new[] { operation }.ToList(),
new CamelCasePropertyNamesContractResolver());
// WHEN we apply this patch document to the foo system model.
patchDocument.ApplyTo(this.fooSystem);
// THEN the system model should contain a modified "test" foo.
this.fooSystem.Foos.ShouldHaveSingleItem();
FooModel foo = this.fooSystem.Foos["test"] as FooModel;
foo.Number.ShouldBe(6);
foo.IsBazzed.ShouldBeFalse();
}
#region Mock Models
private class FooModel
{
[JsonProperty(PropertyName = "number")]
public int Number { get; set; }
[JsonProperty(PropertyName = "bazzed")]
public bool IsBazzed { get; set; }
}
private class FooSystemModel
{
private readonly IDictionary<string, FooModel> foos;
public FooSystemModel()
{
this.foos = new Dictionary<string, FooModel>();
this.Foos = new DynamicDeserialisationStore<FooModel>(
storeValue: (name, foo) => this.foos[name] = foo,
removeValue: name => this.foos.Remove(name),
retrieveValue: name => this.foos[name],
retrieveKeys: () => this.foos.Keys);
}
[JsonProperty(PropertyName = "foos")]
public IDictionary<string, object> Foos { get; }
}
#endregion
}
You could, for instance, deserialize your received Json into an object:
var dataDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
And iterate over it, casting and converting the values of the KeyValuePairs you want to patch into your destination type, CanMessageDefinition:
Dictionary<string, CanMessageDefinition> updateData = new Dictionary<string, CanMessageDefinition>();
foreach (var record in dataDict)
{
CanMessageDefinition recordValue = (CanMessageDefinition)record.Value;
if (yourExistingRecord.KeyAttributes.Keys.Contains(record.Key) && (!yourExistingRecord.KeyAttributes.Values.Equals(record.Value)))
{
updateData.Add(record.Key, recordValue);
}
}
And just save your object to your db.
An alternative would be to do this inside a JsonConverter as you mentioned. Cheers

Arguments on properties

Assuming there's an enumeration defined as follows:
public enum Beep
{
HeyHo,
LetsGo
}
I wonder if it's possible to improve the following property:
public Dictionary<Beep, String> Stuff{ get; set; }
...
String content = Stuff[Beep.HeyHo]
because the way it's right now, I retrieve the dictionary and then pick out the element I need. I wonder if it's (a) possible at all and if so (b) recommended to create something like this pseudo-code.
public String Stuff{ get<Beep>; set<Beep>; }
...
String content = Stuff[Beep.HeyHo]
You can apply an indexer to your class.
It is recommended, as it improves encapsulation. For example, it's perfectly possible using the original code to replace the Dictionary entirely with a different dictionary - which is probable not desirable.
public class MyClass
{
// Note that dictionary is now private.
private Dictionary<Beep, String> Stuff { get; set; }
public String this[Beep beep]
{
get
{
// This indexer is very simple, and just returns or sets
// the corresponding element from the internal dictionary.
return this.Stuff[beep];
}
set
{
this.Stuff[beep] = value;
}
}
// Note that you might want Add and Remove methods as well - depends on
// how you want to use the class. Will client-code add and remove elements,
// or will they be, e.g., pulled from a database?
}
Usage:
MyClass myClass = new MyClass();
string myValue = myClass[Beep.LetsGo];
You can also use an indexer.
class MyClass
{
private readonly Dictionary<Beep, string> _stuff = new Dictionary<Beep, string>();
public string this[Beep beep]
{
get { return _stuff[beep]; }
set { _stuff[beep] = value; }
}
}
Now, instead of calling
var obj = new MyClass();
string result = obj.Stuff[Beep.HeyHo];
You can call
var obj = new MyClass();
string result = obj[Beep.HeyHo];
Indexers work much like properties but have at least one argument used as index. You can have only one indexer per class, however you can create different overloads of it. The same overloading rules apply as for methods.
Something like this using Indexer
public class Stuff
{
public Dictionary<Beep, String> _stuff { get; set; }
public enum Beep
{
HeyHo,
LetsGo
}
public Stuff()
{
_stuff = new Dictionary<Beep, string>();
// add item
_stuff[Beep.HeyHo] = "response 1";
_stuff[Beep.LetsGo] = "response 2";
}
public string this[Beep beep]
{
get { return _stuff[beep]; }
}
}
Sample Usage :
public static class Program
{
private static void Main()
{
Stuff stuff = new Stuff();
string response;
response = stuff[Stuff.Beep.HeyHo]; // response 1
response = stuff[Stuff.Beep.LetsGo]; // response 2
}
}

Categories

Resources