How to serialize a Dictionary<object, guid>? - c#

I'm currently building an application where I have some tasks that are sharing a Dictionary<Object, Guid>.
To avoid conflicts, the actual Dictionaries are contained within a DictionaryHandler-class with three methods:
class DictionaryHandler
{
private object lockProcesses = new object();
private Dictionary<Process, Guid> processes = new Dictionary<Process, Guid>();
public Dictionary<Process, Guid> GetProcesses()
{
lock (lockProcesses)
{
// TODO
}
}
public void AddToProcesses(Process process, Guid guid)
{
lock (lockProcesses)
{
processes.Add(process, guid);
}
}
public void RemoveFromProcesses(Process process)
{
lock (lockProcesses)
{
processes.Remove(process);
}
}
}
For context, this is the Process-class:
public class Process
{
public string Name { get; }
public bool Enabled { get; }
public TimeSpan RuntimeWindowStart { get; }
public TimeSpan RuntimeWindowEnd { get; }
public TimeSpan Cooldown { get; }
public int Priority { get; }
public string Username { get; }
public string ExceptionDate { get; }
public string ExceptionDay { get; }
public string AllowedWorkdays { get; }
public string SpecificResource { get; }
public string Assigned { get; set; }
public DateTime? Timestamp { get; set; }
public Process(string name, bool enabled, TimeSpan runtimeWindowStart, TimeSpan runtimeWindowEnd, TimeSpan cooldown, int priority, string username, string exceptionDate, string exceptionDay, string allowedWorkdays, string specificResource, string assigned, DateTime? timestamp)
{
Name = name;
Enabled = enabled;
RuntimeWindowStart = runtimeWindowStart;
RuntimeWindowEnd = runtimeWindowEnd;
Cooldown = cooldown;
Priority = priority;
Username = username;
ExceptionDate = exceptionDate;
ExceptionDay = exceptionDay;
AllowedWorkdays = allowedWorkdays;
SpecificResource = specificResource;
Assigned = assigned;
Timestamp = timestamp;
}
}
My main issue is that I want to find a way to return a copy of the Dictionary through the GetProcesses()-method, without returning a reference to the "actual" dictionary.
As far as I can see, the optimal way to do this is to Serialize and Deserialize the Dictionary and return that. But I'm having a hard time doing this, as I'm unable to find an example that matches my case.
I've read this and this and tried to combine the two - unfortunately without luck.

My main issue is that I want to find a way to return a copy of the Dictionary through the GetProcesses()-method, without returning a reference to the "actual" dictionary.
If you don't need to clone the values, you can use the constructor overload to Dictionary which takes an existing IDictionary:
new Dictionary<Process, Guid>(processes);
If you do need to clone the values, you can use something like:
public static Dictionary<Process, Guid> DeepClone<TKey, TValue>(Dictionary<Process, Guid> source)
{
var ret = new Dictionary<Process, Guid>(source.Count, source.Comparer);
foreach (var entry in source)
{
ret.Add(entry.Key, entry.Value);
}
return ret;
}
If you do need create a copy of Process class instance while copying dictionary, you may use:
public class Process
{
// some properties here
public Process ShallowCopy()
{
return (Process) this.MemberwiseClone();
}
}
public static Dictionary<Process, Guid> DeepClone<TKey, TValue>(Dictionary<Process, Guid> source)
{
var ret = new Dictionary<Process, Guid>(source.Count, source.Comparer);
foreach (var entry in source)
{
ret.Add(entry.Key.ShallowCopy(), entry.Value);
}
return ret;
}

Use String instead of Guid.
Guid is structure type. Therefore serialize and deserialize methods might not work correctly.

Related

What's the accepted way to handle values that can be different data types in C#?

I'm basically reading a config file
[Section]
Key=value
Where the value can be either a string, an integer, a double, or a boolean value.
While working in this context, I have a class that looks like this...
public class Setting
{
public string Section {get; set;}
public string Key {get; set;}
public <string, int, double, or bool> Value {get; set;}
public Setting(string section, string key, <string, int, double, or bool> value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
//if Value is an int, call third-party code to write an integer to the config file.
//if Value is a string, call third-party code to write a string to the config file.
//...
}
}
In this situation, what is the accepted way to handle the Value property of this class?
In addition, I'd like to be able to store a bunch of these objects in an Array, List, or other types of collections.
UPDATE:
I'm not reading/writing to the configuration file directly, that part of the code is not controlled by me. Basically, I need to call different functions in the third-party code, based on the type of Value
UPDATE:
One thought was to use generics, and have a class like this...
public class Setting<T>
{
public string Section { get; set; }
public string Key { get; set; }
public T Value { get; set; }
public Setting(string section, string key, T value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
switch (Type.GetTypeCode(typeof(T)))
{
case TypeCode.Int32:
//Call third-party code to write an integer
break;
case TypeCode.String:
//Call third-party code to write a string
break;
default:
break;
}
}
}
But then I'd only be able to store a single type of setting in a List.
System.Collections.Generic.List<Setting<string>> settings = new List<Setting<string>>();
So I'd have to have a list for each type of setting.
UPDATE:
Another option might be to use and interface, and classes for each type of setting that implement the interface...
interface ISetting
{
string Section { get; set; }
string Key { get; set; }
void Write();
}
public class StringSetting : ISetting
{
public string Section { get; set; }
public string Key { get; set; }
public string Value { get; set; }
public StringSetting(string section, string key, string value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
//Call third-party code to write the setting.
}
}
But that seems like a lot of duplicate code, so making changes in the future might be error prone.
UPDATE:
Another option, is to make Value a dynamic type.
public class DynamicSetting
{
public string Section { get; set; }
public string Key { get; set; }
public dynamic Value { get; set; }
public DynamicSetting(string section, string key, dynamic value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
switch (Type.GetTypeCode(Value.GetType()))
{
case TypeCode.Int32:
//Call third-party code to write an integer
break;
case TypeCode.String:
//Call third-party code to write a string
break;
default:
break;
}
}
}
Then I can create a bunch of DynamicSetting objects, and store them in a collection like I want.
DynamicSetting IntSetting = new DynamicSetting("Section", "Key", 1);
DynamicSetting StringSetting = new DynamicSetting("Section", "Key", "1");
DynamicSetting DoubleSetting = new DynamicSetting("Section", "Key", 1.0);
System.Collections.Generic.List<DynamicSetting> settings = new List<DynamicSetting>();
settings.Add(IntSetting);
settings.Add(StringSetting);
settings.Add(DoubleSetting);
foreach(DynamicSetting setting in settings)
{
setting.Write();
}
UPDATE:
I could also make Value an object
public class ObjectSetting
{
public string Section { get; set; }
public string Key { get; set; }
public object Value { get; set; }
public ObjectSetting(string section, string key, object value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
switch (Type.GetTypeCode(Value.GetType()))
{
case TypeCode.Int32:
//Call third-party code to write an integer
break;
case TypeCode.String:
//Call third-party code to write a string
break;
case TypeCode.Double:
//Call third-party code to write a string
break;
default:
break;
}
}
}
And it would work just like dynamic
ObjectSetting IntSetting = new ObjectSetting("Section", "Key", 1);
ObjectSetting StringSetting = new ObjectSetting("Section", "Key", "1");
ObjectSetting DoubleSetting = new ObjectSetting("Section", "Key", 1.0);
System.Collections.Generic.List<ObjectSetting> settings = new List<ObjectSetting>();
settings.Add(IntSetting);
settings.Add(StringSetting);
settings.Add(DoubleSetting);
foreach(ObjectSetting setting in settings)
{
setting.Write();
}
The simplest way is to accept Value as an object in the constructor and the setter, both of which would validate the Type against your list of valid types. Use a Switch in your Write method to determine which third-party code to call. You can store all your Settings in a single collection. Alternatively, you could write overloads for the constructor and a SetValue method. That's a little more code, but would provide design time type-checking.
Example for ISettingValue:
public interface ISettingValue
{
void Write();
}
public class StringSetting : ISettingValue
{
readonly string _data;
public StringSetting(string data) => _data = data;
public void Write()
{
//Call third-party code to write the string (value of _data).
}
}
public class IntSetting : ISettingValue
{
readonly int _data;
public IntSetting(int data) => _data = data;
public void Write()
{
//Call third-party code to write the integer (value of _data).
}
}
public class Setting
{
public string Section { get; set; }
public string Key { get; set; }
public ISettingValue Value { get; set; }
public Setting(string section, string key, ISettingValue value)
{
Section = section;
Key = key;
Value = value;
}
public void Write()
{
Value.Write();
}
}
Maybe something like that?
public abstract class Setting {
public abstract Type keyType { get; }
public string Key { get; protected set; }
public object value { get; protected set; }
protected abstract Action writer { get; }
public void Write() => writer();
}
public class Setting<T> : Setting {
public override Type keyType => typeof(T);
protected override Action writer => () => typeWriter(Value);
public string Section { get; set; }
public T Value {get; set;}
private Action<T> typeWriter { get; }
public Setting(string section, string key, T value, Action<T> writer) {
Section = section;
Key = key;
this.value = Value = value;
typeWriter = writer;
}
}
public class Usage {
private List<Setting> settings = new List<Setting>() {
new Setting<double>("", "x", 10, n => Debug.WriteLine(n % 4)),
new Setting<string>("", "y", "abc", s => Debug.WriteLine(s.ToUpper())),
new Setting<bool>("", "z", true, b => Debug.Write(!b)),
};
public Usage() {
foreach (var s in settings) {
Debug.Write($"{s.keyType.Name} {s.Key} =");
s.Write();
}
}
}

make a snapshoot object of the current status of a static class

I have a static class in my system keeping track of the frequency of measurements, the number of samples currently read, what sensors are on an which are off and all those nice details.
Now I make a measurement and want to create a report in the report I want to save all the information stored in the static class. something like this :
public static class Details{
public static int samplesRead { get; set;}
public static int frequency { get; set;}
public static List<devices> devices { get; set;}
}
public class Patient{...} // name, surname , blabla
public class ResultsSet {
public DateTime date;
public Patient patient;
public *DetailsObject* details;
}
public void main {
patient p = new patient(...);
... make the measurements ...
var results = new ResultSet();
results.patient = p;
results.DateTime = DateTime.Now();
results.details = **here the magic ** Details.ToObject();
results.Serialize(myFilePath);
}
How can one acomplish that conversion to a single defined object?
it is the capability of making an snapshot of the static class in an object. [...] Just make an object.
So what you could do is to create a DTO that has the same properties as your static class:
public class DetailsSnapshot
{
public int samplesRead { get; set; }
public int frequency { get; set; }
public List<device> devices { get; set; }
}
Not you can map and return such an object at any given time:
public static class Details{
public static int samplesRead { get; set;}
public static int frequency { get; set; }
public static List<device> devices { get; set; }
public static DetailsSnapshot MakeSnapShot()
{
return new DetailsSnapshot
{
samplesRead = samplesRead,
frequency = frequency,
devices = devices.ToList()
};
}
}
You can have then such an snap-shot-object in your results:
public class ResultsSet
{
public DateTime date;
public Patient patient;
public DetailsSnapshot detailsSnapShot;
}
and make the snap shot (here the magic) the following way:
results.detailsSnapShot = Details.MakeSnapShot();
EDIT:
There is also a way using reflection. With this approach you would scan your Details class for the properties and extract the values. You could return a Dictionary which basically maps the names of the properties to the values:
public static Dictionary<string, object> MakeSnapShotReflection()
{
PropertyInfo [] allPorperties = typeof(Details).GetProperties(BindingFlags.Public | BindingFlags.Static);
Dictionary<string, object> valuemapping = new Dictionary<string, object>();
for (int i = 0; i < allPorperties.Length; i++)
{
valuemapping.Add(allPorperties[i].Name, allPorperties[i].GetValue(null));
}
return valuemapping;
}
This way would allow you to extend the Details class with further properties without worrying about extending anything else.
Or the short version:
public static Dictionary<string, object> MakeSnapShotReflection()
{
PropertyInfo[] allPorperties = typeof(Details).GetProperties(BindingFlags.Public | BindingFlags.Static);
return allPorperties.ToDictionary(key => key.Name, value => value.GetValue(null));
}
With this approach you could still use intellisens to access the correct values:
Test Data:
public static class Details
{
public static int samplesRead { get; set;} = 100;
public static int frequency { get; set; } = 2700;
public static List<device> devices { get; set; } = new List<device>()
{
new device { Name = "sensor1" },
new device { Name = "sensor 2" }
};
}
public class device
{
public string Name { get; set; }
}
Test Code to access values:
void Main()
{
Dictionary<string, object> details = Details.MakeSnapShotReflection();
Console.WriteLine(details[nameof(Details.frequency)]);
Console.WriteLine(details[nameof(Details.samplesRead)]);
foreach (var element in details[nameof(Details.devices)] as IEnumerable<device>)
{
Console.WriteLine(element.Name);
}
}
OUTPUT:
2700
100
sensor1
sensor 2
If you want to save and restore it, make it a non-static class and serialise/deserialise it using JSON or XML. You can then go JsonConvert.SerialiseObject and JsonConvert.Deserialise object. Nice and simple.
If you want to ensure only one instance, make the class a singleton.
public class Details
{
private static readonly Details _instance = new Details();
static Details()
{
}
private Details()
{
}
public Details Intance
{
get
{
return _instance;
}
}
public int samplesRead { get; set;}
public int frequency { get; set;}
public List<devices> devices { get; set; }
}
Then you can access it's properties this way:
Details.Instance.samplesRead
If the class has to be static, you can use reflection to serialise it:
public static string SerializeStaticProperties(Type type)
{
var properties = type.GetProperties(BindingFlags.Static | BindingFlags.Public);
var data = new List<Property>();
foreach (var property in properties)
{
data.Add(new Property
{
Name = property.Name,
Type = property.PropertyType,
Value = JsonConvert.SerializeObject(property.GetValue(null))
});
}
return JsonConvert.SerializeObject(data);
}
public static void DeserializeStaticProperties(Type type, string json)
{
var data = JsonConvert.DeserializeObject<List<Property>>(json);
foreach (var item in data)
{
var property = type.GetProperty(item.Name, BindingFlags.Static | BindingFlags.Public);
if (property != null)
{
property.SetValue(null, JsonConvert.DeserializeObject(item.Value, item.Type));
}
}
}
public class Property
{
public string Name { get; set; }
public Type Type { get; set; }
public string Value { get; set; }
}

Deserializing many Json files using Newtonsoft ToObject

Is there anything terribly inefficient here? It seems like this process is taking way longer than it should. I am parsing many JSON files each with a JsonArray of objects. Maybe someone with more experience could point out an error in this method of parsing the JSON into objects, thereby saving me a ton of time.
Also, memory usage slowly creeps upwards MB by MB sometimes causing outofmemoryexceptions..
public void Parse(){
using (BabysFirstsUsersDataEntities db = new BabysFirstsUsersDataEntities()
{
foreach (var path in Directory.EnumerateFiles(#"C:\\examplepath\").OrderBy(f => f))
{
string jsonString = System.IO.File.ReadAllText(path);
JToken tok = JObject.Parse(jsonString);
Debug.WriteLine("path: " + path);
foreach (var x in tok.First.First)
{
JsonUserImageDTO jdto = x.ToObject<JsonUserImageDTO>();
UserImageList uil = jdto.ToDataModel();
if (uil.REID != null)
db.UserImageLists.Add(uil);
}
}
db.SaveChanges();
}
}
An example of what one of the JSON strings in each .json file looks like below. Note that there are around 1000 of these files and each can have thousands of such entries:
{
"results": [
{
"ACL": {
"asdf": {
"read": true,
"write": true
},
"role:admin": { "read": true }
},
"REID": "exampleID",
"createdAt": "datetime-string",
"email": "example",
"objectId": "example",
"updatedAt": "datetimestring",
"urlCount": 1,
"urlList": [ "exampleurl" ]
},
{
"ACL": {
"asdf": {
"read": true,
"write": true
},
"role:admin": { "read": true }
},
"REID": "exampleID",
"createdAt": "datetime-string",
"email": "example",
"objectId": "example",
"updatedAt": "datetimestring",
"urlCount": 1,
"urlList": [ "exampleurl" ]
}
]
}
It looks like there could be several places that could causing the slowness.
Deserialzing JSON
Transforming the object twice (jdto, then uil)
Saving to the database
It may be worth profiling the code to find out exactly what part is taking longer than you'd expect. That said there are some things you can do to generally improve this code.
Deserialize from a steam instead of a string. The way you have it, you basically have the object in memory twice-- once as a string, then once as tok. See the second example in the docs for how to use a stream. Actually, in your case you the same information in memory 4 times -- the string, tok, jdto, and uil. Which brings me to the next point..
Try to eliminate some of the intermediate representations of your object. Generally, the more objects you have laying around, the more time you will spend waiting on the GC.
Move the filtering on the path name to the part where you call EnumerateFiles(). There is no sense in deserializing a file if you are not going to do anything with it.
Have you actually profiled your code? See Erik Lippert's performance rant: Use a profiler or other analysis tool to determine empirically where the bottleneck is before you start investigating alternatives. For instance, you actual performance problem may be somewhere in the BabysFirstsUsersDataEntities db class.
That being said, my immediate reaction is that you have too many intermediate representations of your data, the construction, population and garbage collection of which all take time. These include:
The jsonString which may be large enough to go on the large object heap, and thus permanently impair the performance and memory use of your process.
The JToken tok representation of your entire JSON hierarchy.
Each individual JsonUserImageDTO.
What I would suggest is to eliminate as many of these intermediate representations as possible. As suggested in the documentation you should load directly from a stream rather that loading to a string and parsing that string.
You can also eliminate the JToken tok by populating your data model directly. Let's say your BabysFirstsUsersDataEntities looks like this (I'm just guessing here):
public class BabysFirstsUsersDataEntities
{
public BabysFirstsUsersDataEntities() { this.UserImageLists = new List<UserImageList>(); }
public List<UserImageList> UserImageLists { get; set; }
}
public class UserImageList
{
public string email { get; set; }
public List<string> urlList;
}
And your DTO model looks something like this model provided by http://json2csharp.com/:
public class RootObjectDTO
{
public ICollection<JsonUserImageDTO> results { get; set; }
}
public class JsonUserImageDTO
{
public ACL ACL { get; set; }
public string REID { get; set; }
public string createdAt { get; set; }
public string email { get; set; }
public string objectId { get; set; }
public string updatedAt { get; set; }
public int urlCount { get; set; }
public List<string> urlList { get; set; }
public UserImageList ToDataModel()
{
return new UserImageList { email = email, urlList = urlList };
}
}
public class Asdf
{
public bool read { get; set; }
public bool write { get; set; }
}
public class RoleAdmin
{
public bool read { get; set; }
}
public class ACL
{
public Asdf asdf { get; set; }
[JsonProperty("role:admin")]
public RoleAdmin RoleAdmin { get; set; }
}
Then create the following generic ConvertingCollection<TIn, TOut> utility class:
public class ConvertingCollection<TIn, TOut> : BaseConvertingCollection<TIn, TOut, ICollection<TIn>>
{
readonly Func<TOut, TIn> toInner;
public ConvertingCollection(Func<ICollection<TIn>> getCollection, Func<TIn, TOut> toOuter, Func<TOut, TIn> toInner)
: base(getCollection, toOuter)
{
if (toInner == null)
throw new ArgumentNullException();
this.toInner = toInner;
}
protected TIn ToInner(TOut outer) { return toInner(outer); }
public override void Add(TOut item)
{
Collection.Add(ToInner(item));
}
public override void Clear()
{
Collection.Clear();
}
public override bool IsReadOnly { get { return Collection.IsReadOnly; } }
public override bool Remove(TOut item)
{
return Collection.Remove(ToInner(item));
}
public override bool Contains(TOut item)
{
return Collection.Contains(ToInner(item));
}
}
public abstract class BaseConvertingCollection<TIn, TOut, TCollection> : ICollection<TOut>
where TCollection : ICollection<TIn>
{
readonly Func<TCollection> getCollection;
readonly Func<TIn, TOut> toOuter;
public BaseConvertingCollection(Func<TCollection> getCollection, Func<TIn, TOut> toOuter)
{
if (getCollection == null || toOuter == null)
throw new ArgumentNullException();
this.getCollection = getCollection;
this.toOuter = toOuter;
}
protected TCollection Collection { get { return getCollection(); } }
protected TOut ToOuter(TIn inner) { return toOuter(inner); }
#region ICollection<TOut> Members
public abstract void Add(TOut item);
public abstract void Clear();
public virtual bool Contains(TOut item)
{
var comparer = EqualityComparer<TOut>.Default;
foreach (var member in Collection)
if (comparer.Equals(item, ToOuter(member)))
return true;
return false;
}
public void CopyTo(TOut[] array, int arrayIndex)
{
foreach (var item in this)
array[arrayIndex++] = item;
}
public int Count { get { return Collection.Count; } }
public abstract bool IsReadOnly { get; }
public abstract bool Remove(TOut item);
#endregion
#region IEnumerable<TOut> Members
public IEnumerator<TOut> GetEnumerator()
{
foreach (var item in Collection)
yield return ToOuter(item);
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
You can now populate your db directly as follows:
var rootDTO = new RootObjectDTO
{
results = new ConvertingCollection<UserImageList, JsonUserImageDTO>(() => db.UserImageLists, (x) => { throw new NotImplementedException(); }, (x) => x.ToDataModel())
};
using (var stream = File.Open(path, FileMode.Open))
using (var reader = new StreamReader(stream))
{
JsonSerializer.CreateDefault().Populate(reader, rootDTO);
}
By populating a preallocated rootDTO and ConvertingCollection<UserImageList, JsonUserImageDTO>, your db.UserImageLists will get populated with the contents of the JSON with fewer intermediate representations.
You can create the objects and then deserialize them.
Example:
JsonConvert.DeserializeObject<RootObject>(jsonString);
public class Asdf
{
public bool read { get; set; }
public bool write { get; set; }
}
public class RoleAdmin
{
public bool read { get; set; }
}
public class ACL
{
public Asdf asdf { get; set; }
public RoleAdmin { get; set; }
}
public class Result
{
public ACL ACL { get; set; }
public string REID { get; set; }
public string createdAt { get; set; }
public string email { get; set; }
public string objectId { get; set; }
public string updatedAt { get; set; }
public int urlCount { get; set; }
public List<string> urlList { get; set; }
}
public class RootObject
{
public List<Result> results { get; set; }
}

Way to set property depending on other property

So, I have this code
Process[] processesManager = Process.GetProcesses();
List<ProcessInfo> temporaryProcessesList = new List<ProcessInfo>();
for (int i = 0; i < processesManager.Length; ++i)
{
temporaryProcessesList.Add(new ProcessInfo(processesManager[i].ProcessName, processesManager[i].Id, TimeSpan.Zero, "Group"));
}
processesList = temporaryProcessesList.GroupBy(d => new {d.Name}).Select(d => d.First()).ToList();
This code is used for getting current processes. Then I'm adding those procesess to temporaryProcessesList. And instead of simple string "Group" I want to set the property depending of the name of process. For example if process has name leagueoflegends.exe then I would like to set the group to "Games", if its devenv.exe I would like to set the group to "Software development".
And my question is, how to do it the simplest/best way? I was thinking about using Dictionary with string and enum. And comparing the ProcessName with string. But maybe there is better way to do it.
ProcessInfo is simple class with 4 properties and constructor.
public class ProcessInfo
{
private string Name { get; set; }
private int Id { get; set; }
private TimeSpan Time { get; set; }
private string Group { get; set; }
public ProcessInfo(string name, int id, TimeSpan time, string group)
{
Name = name;
Id = id;
Time = time;
Group = group;
}
}
Using dictionary is the best way to accomplish this:
var dictionary = new Dictionary<string, string>();
dictionary.Add("a.exe", "aGroup");
dictionary.Add("b.exe", "bGroup");
string val;
if (dictionary.TryGetValue(processName, out val))
processInfo.Group = val;
else
processInfo.Group = "Undefined Group";
Maybe this is what you are looking for:
public class ProcessInfo
{
private string _name;
private string Name
{
get { return _name; }
set
{
_name = value;
UpdateGroupName();
}
}
private int Id { get; set; }
private TimeSpan Time { get; set; }
private string Group { get; set; }
private void UpdateGroupName()
{
Group = ProcessNames::GetGroupFromProcessName(Name);
}
public ProcessInfo(string name, int id, TimeSpan time)
{
Name = name;
Id = id;
Time = time;
}
}
internal static class ProcessNames
{
private static Dictionary<string, string> _names;
public static string GetGroupNameFromProcessName(string name)
{
// Make sure to add locking if there is a possibility of using
// this from multiple threads.
if(_names == null)
{
// Load dictionary from JSON file
}
// Return the value from the Dictionary here, if it exists.
}
}
This design isn't perfect, but hopefully you see the idea. You could also move the update of the Group name to the constructor, but then it would not change the Group name if you set the property after construction.
Also, you could clean the interface up by using INotifyPropertyChanged and/or dependency injection. https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx

Base class isn't Deserialized

I am using Newtonsoft.Json .Net for 4.0 for this project
Parent class:
public class CLiveThing
{
private object lawk = new object();
public Action<double> hp_cur_changed;
public Action<double> hp_max_changed;
public double hp_max { get; private set; }
public double hp_cur { get; private set; }
public void change_hp_max(double val)
{
lock (lawk)
{
hp_max += val;
if (hp_max_changed != null)
hp_max_changed(hp_max);
}
}
public void change_hp_cur(double val)
{
lock (lawk)
{
hp_cur += val;
if (hp_cur_changed != null)
hp_cur_changed(hp_cur);
}
}
}
Child class:
public class CPlayer : CLiveThing
{
public int id { get; private set; }
public CPlayer(int id)
{
this.id = id;
}
/*
* Network
*/
public string Serialize()
{
return Newtonsoft.Json.JsonConvert.SerializeObject(this);
}
public static CPlayer Deserialize(string val)
{
return Newtonsoft.Json.JsonConvert.DeserializeObject<CPlayer>(val);
}
}
Server (uses Players.CPlayers to manage all players with a generic collection)
Players.CPlayers.Serialize()
Players.CPlayers.Serialize serializes all players in the server's memory, one per line
Like so:
public static string Serialize()
{
players_lock.AcquireReaderLock(Timeout.Infinite);
string str = "";
foreach (CPlayer player in players.Values)
{
str += player.Serialize();
str += Environment.NewLine;
}
players_lock.ReleaseReaderLock();
return str;
}
Client
I put a break line in the Players.CPlayers.Deserialize loop, which reverses what the server did.
foreach (string line in split)
{
if (line.Length > 0)
{
CPlayer player = CPlayer.Deserialize(line);
addOrReplace(player.id, player);
}
}
Here's an example of one line:
What goes in:
"{\"hp_cur_changed\":null,\"hp_max_changed\":null,\"id\":1,\"hp_max\":100.0,\"hp_cur\":100.0}"
What comes out of CPlayer.Deserialize():
It only Deserialized the ID and ignored the properties in the parent class. Which is weird because the server-side did Serialize it properly. Can anyone tell me how to fix this?
I was not able to find an official reference why it's working like this but there are at least two way to solve your problem:
Declare your base class property setters as public
public double hp_cur { get; set; }
public double hp_max { get; set; }
Or annotate them with the JsonProperty attribute:
[JsonProperty]
public double hp_max { get; private set; }
[JsonProperty]
public double hp_cur { get; private set; }

Categories

Resources