Understanding Protobuf-net serialization and deserialization of properties - c#

I'm doing some tests with the Protobuf-net serializer and was experimenting with the serialization of properties. Basically i wanted to store a dictionary(string, int) as a dictionary(string, string) and then on deserialization convert the (string, string) back to a (string, int). However, much to my surprise it goes through the getter on TestDictionary on deserialization (and then threw a null reference exception) which confused me a lot. I would think it goes through the setter on deserialization. So, essentially I'm not sure how property serialization is supposed to function. The simple test class I wrote is below:
[ProtoContract]
public class Class1
{
[ProtoMember(2)]
public int test;
public Dictionary<string, int> testDictionary;
//public Dictionary<string, string> testDictionaryString;
[ProtoMember(3)]
private string test2;
[ProtoMember(4)]
private string test3;
[ProtoMember(5)]
private string test4;
public Class1()
{}
public Class1(int test)
{
this.test = test;
this.testDictionary = new Dictionary<string, int>();
for (int i = 0; i < test; i++)
{
this.testDictionary.Add("a" + i.ToString(), i);
}
test2 = (test + 1).ToString();
test3 = (test + 2).ToString();
test4 = (test + 3).ToString();
}
[ProtoMember(1)]
public Dictionary<string, string> TestDictionary
{
get
{
Dictionary<string, string> temp = new Dictionary<string, string>();
foreach (KeyValuePair<string, int> pair in this.testDictionary)
{
temp.Add(pair.Key, pair.Value.ToString());
}
return temp;
}
set
{
testDictionary = new Dictionary<string, int>();
foreach (KeyValuePair<string, string> pair in value)
{
testDictionary.Add(pair.Key, Convert.ToInt32(pair.Value));
}
}
}

For the purposes of serialization, dictionaries are treated just like lists.
You can imagine the default list serialization as something like (assuming that there is a set available):
var list = obj.TheProperty;
if(list == null) {
list = new TheListType();
obj.TheProperty = list;
}
do {
list.Add(DeserializeTheItemType(reader));
} while ({still that field})
However, you can influence it. Simply adding OverwriteTrue = true may be sufficient for your needs:
[ProtoMember(1, OverwriteList = true)]
public Dictionary<string, string> TestDictionary {...}
This should now do something more like:
var list = new TheListType();
do {
list.Add(DeserializeTheItemType(reader));
} while ({still that field})
obj.TheProperty = list;
An important consequence here, however, is that Merge will no longer work in the usual expected way.
As a side note: your get/set should probably pass nulls through, so that if testDictionary is null, TestDictionary returns null; and if TestDictionary is set to null, then testDictionary is set to null.

Related

Convert enum to Dictionary<int,string> but string is the description attribute

I try to convert an enum to Dictionary int is the value and string is the description of the value.
I already have a function that gets the enum description by it's value but I don't how to use it with the enum iteration I have:
public static IDictionary<int, string> ConvertEnumToDictionary<K>()
{
Dictionary<int, string> mydic = new Dictionary<int, string>();
foreach (K foo in Enum.GetValues(typeof(K)))
{
//???
mydic.Add((int)foo, GetEnumDescription(foo));
}
}
public static string GetEnumDescription(Enum value)
{
// Get the Description attribute value for the enum value
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
public enum Lu_LanguageTypes
{
[Description("Hebrew")]
he = 1,
[Description("Englishj")]
en = 2,
[Description("Spanish")]
es = 3
}
You can modify ConvertEnumToDictionary method a little bit and apply where K : Enum generic constraint (available from C# 7.3) and cast Enum value to K before passing to GetEnumDescription method
public static IDictionary<int, string> ConvertEnumToDictionary<K>() where K : Enum
{
var mydic = new Dictionary<int, string>();
foreach (var foo in Enum.GetValues(typeof(K)))
{
mydic.Add((int)foo, GetEnumDescription((K)foo));
}
return mydic;
}
Example of the usage, which gives a dictionary with 3 key-value pairs
var result = ConvertEnumToDictionary<Lu_LanguageTypes>();
Another option is to add constraint to IConvertible interface as well (since Enum type implements it) and avoid casting
public static IDictionary<int, string> ConvertEnumToDictionary<K>() where K : Enum, IConvertible
{
var mydic = new Dictionary<int, string>();
foreach (K foo in Enum.GetValues(typeof(K)))
{
mydic.Add(foo.ToInt32(null), GetEnumDescription(foo));
}
return mydic;
}

Missing changes in Dictionary

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?

Generate dynamic object from dictionary with C # Reflection

I've been researching a bit about reflections in C # and would like to know if I use a dictionary with keys-values ​​can create an object with the variable with the name of each key in the dictionary and their values​​, the key value of that dictionary.
I have a method that does the opposite, that extracts an object from a dictionary, this dictionary contains the keys and the class properties and their values​​, the value of the properties.
I wonder how to do this if possible.
Below is my method, which extracts a dictionary of an object:
protected Dictionary<String, String> getObjectProperty(object objeto)
{
Dictionary<String, String> dictionary = new Dictionary<String, String>();
Type type = objeto.GetType();
FieldInfo[] field = type.GetFields();
PropertyInfo[] myPropertyInfo = type.GetProperties();
String value = null;
foreach (var propertyInfo in myPropertyInfo)
{
if (propertyInfo.GetIndexParameters().Length == 0)
{
value = (string)propertyInfo.GetValue(objeto, null);
value = value == null ? null : value;
dictionary.Add(propertyInfo.Name.ToString(), value);
}
}
return dictionary;
}
If you've already got a dictionary, I'd avoid reflection and just use DynamicObject
For example:
public class DynamicDictionary : DynamicObject
{
private readonly Dictionary<string, object> dictionary;
public DynamicDictionary(Dictionary<string, object> dictionary)
{
this.dictionary = dictionary;
}
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
return dictionary.TryGetValue(binder.Name, out result);
}
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
dictionary[binder.Name] = value;
return true;
}
}
Which can be used as follows:
dynamic x = new DynamicDictionary(
new Dictionary<string, object> {{"Name", "Peter"}});
Console.WriteLine(x.Name);
I am not sure if this is what you're looking for, but judging by your question, I think you want to
instantiate types at run time from the types located in a dictionary, which will be obtained by providing a key.
If that is so, then you can create the following class which will hold key-value pairs of strings which will be your keys, and Types which will represent your values which will be instantiated.
class DictionaryActivator
{
Dictionary<string, Type> Dictionary = new Dictionary<string, Type>();
public DictionaryActivator()
{
Dictionary.Add("MyCar", typeof(Car));
Dictionary.Add("MyHouse", typeof(House));
Dictionary.Add("MyFruit", typeof(Fruit));
Dictionary.Add("MyComputer", typeof(Computer));
}
public T GetInstance<T>(string type, params object[] parameters)
{
if (parameters.Count() == 0)
{
return (T)Activator.CreateInstance(Dictionary[type]);
}
else
{
return (T)Activator.CreateInstance(Dictionary[type], parameters.ToArray());
}
}
}
You can also create four test classes to test this setup.
class House
{
public int Number = 25;
}
class Car
{
public double Price = 50000;
}
class Fruit
{
public string Name = "Apple";
}
class Computer
{
public string Cpu { get; set; }
public string Gpu { get; set; }
public Computer(string cpu, string gpu)
{
Cpu = cpu;
Gpu = gpu;
}
}
Once this is done, you can run the following lines of code to get all the types from the dictionary, instantiate them and cast them to appropriate types. As you might notice, the last Computer example is showing you how to add multiple parameters (in this case two) to the newly created instance and return it as an instance of type object.
In the end you can cast it to the Computer type so you can check that the constructor parameters actually went to the corresponding properties.
class Program
{
static void Main()
{
var source = new DictionaryActivator();
Console.WriteLine(source.GetInstance<Car>("MyCar").Price);
Console.WriteLine(source.GetInstance<House>("MyHouse").Number);
Console.WriteLine(source.GetInstance<Fruit>("MyFruit").Name);
var computer = source.GetInstance<object>("MyComputer", "Fast CPU", "Fast GPU");
Console.WriteLine((computer as Computer).Cpu);
Console.WriteLine((computer as Computer).Gpu);
Console.Read();
}
}
Since ExpandoObject is a dictionary, you can use this extension function:
public static object With(this IDictionary<string, object> obj, IDictionary<string,object> additionalProperties)
{
foreach (var name in additionalProperties.Keys)
obj[name] = additionalProperties[name];
return obj;
}
Usage:
var dynamicObj = new System.Dynamic.ExpandoObject().With(myDictionary);

Universal classes field parser to Dictionary<String, String> using reflection

I have a lot of times thinking about converting example of class to Dictionary<String, String> where key is variable name(class field name) and value is variable current assigned value. So we have a simple class:
public class Student
{
public String field1;
public Int64 field2;
public Double field3;
public Decimal field4;
public String SomeClassMethod1()
{
...
}
public Boolean SomeClassMethod2()
{
...
}
public Int64 SomeClassMethod1()
{
...
}
}
How I expect it will look like:
static void Main(String[] args)
{
Student student = new Student(){field1 = "", field2 = 3, field3 = 3.0, field4 = 4.55m};
Dictionary<String, String> studentInDictionary = ConvertAnyToDictionary<Student>(student);
}
public Dictionary<String, String> ConvertAnyToDictionary<T>(T value) where T:class
{
...
}
Any ideas about how to make it real? Thx a lot for any advices.
EDIT1:
Expected result:
studentInDictionary[0] = KeyValuePair("field1", "");
studentInDictionary[1] = KeyValuePair("field2", (3).ToString());
studentInDictionary[2] = KeyValuePair("field3", (3.0).ToString());
studentInDictionary[3] = KeyValuePair("field4", (4.55m).ToString());
Here is how you can do it:
public static Dictionary<String, String> ConvertAnyToDictionary<T>(T value) where T : class {
var fields = typeof(T).GetFields();
var properties = typeof(T).GetProperties();
var dict1 = fields.ToDictionary(x => x.Name, x => x.GetValue(value).ToString());
var dict2 = properties.ToDictionary(x => x.Name, x => x.GetValue(value, null).ToString());
return dict1.Union(dict2).ToDictionary(x => x.Key, x=> x.Value);
}
Edit: I'm taking in count both fields and properties there. If you will only be using properties, you can just use dict2.
You might want to take a look at the BindingFlags argument received by GetFields() and GetProperties() methods.
var proInfos = student.GetType().GetProperties();
if(proInfos!=null)
{
Dictionary<string,string> dict= new Dictionary<string, string>();
foreach (var propertyInfo in proInfos)
{
var tv = propertyInfo.GetValue(currentObj, null);
if(tv!=null)
{
if(dict.ContainsKey(propertyInfo.Name))
continue;
dict.Add(propertyInfo.Name, tv.ToString());
}
}
}
You can either serialize using already existing Serializers (Xml or JSON) or you can go about it using reflection.
Here is an example of how to get fields with reflection:
Not getting fields from GetType().GetFields with BindingFlag.Default

how to implement class with collection of string/object pairs so that an object can be returned with generic method?

The values in a file are read as string and can be double, string or int or maybe even lists. An example file:
DatabaseName=SomeBase
Classes=11;12;13
IntValue=3 //this is required!
DoubleValue=4.0
I was thinking something like this:
class ConfigValues
{
private static SomeObject _utiObject;
private static string _cfgFileName = "\\SomeSettings.cfg";
private static Dictionary<string, Type> _settingNamesAndTypes =
new Dictionary<string, Type>();
private static Dictionary<string, object> _settings = new Dictionary<string, object>();
private static string _directory = string.Empty;
const string _impossibleDefaultValue = "987ABC654DEF321GHI";
public static T GetConfigValue<T>(string cfgName)
{
object value;
if (_settings.TryGetValue(cfgName, out value))
return (T)value;
else
return default(T);
}
public static bool LoadConfig(Dictionary<string, Type> reqSettings,
Dictionary<string, Type> optSettings,
Dictionary<string, object> optDefaultValues, out string errorMsg)
{
errorMsg = string.Empty;
try
{
_utiObject = new SomeObject(new string[] { "-c", CfgFileNameAndPath });
}
catch (Exception e)
{
errorMsg = string.Format("Unable to read {0}. Exception: {1}",
CfgFileNameAndPath, e.Message);
return false;
}
foreach (KeyValuePair<string, Type> kVPair in reqSettings)
{
if (!ReadCheckAndStore(kVPair, null, out errorMsg))
return false;
_settingNamesAndTypes.Add(kVPair.Key, kVPair.Value);
}
foreach (KeyValuePair<string, Type> kVPair in optSettings)
{
if (!ReadCheckAndStore(kVPair, optDefaultValues[kVPair.Key], out errorMsg))
return false;
_settingNamesAndTypes.Add(kVPair.Key, kVPair.Value);
}
return true;
}
private static bool ReadCheckAndStore(KeyValuePair<string, Type> kVPair, object defaultValue, out string errorMsg)
{
errorMsg = string.Empty;
string usedDefaultValue, value = string.Empty;
/* required setting */
if (defaultValue == null)
usedDefaultValue = _impossibleDefaultValue;
else
usedDefaultValue = defaultValue.ToString();
//all string parameters below
_utiObject.GetConfigValue(kVPair.Key, usedDefaultValue, ref value);
if (_impossibleDefaultValue == value)
{
errorMsg = string.Format("Required configuration setting {0} was not" +
"found in {1}", kVPair.Key, CfgFileNameAndPath);
return false;
}
Type type = kVPair.Value;
_settings[kVPair.Key] = Convert.ChangeType(value, type);
return true;
}
}
PS. Additional issue is default values for optional settings. It's not elegant to pass them to LoadConfig in separate Dictionary, but that is an other issue...
The only way I can think of doing this is to have Dictionary<String,Object> and then cast the Object to the appropriate type.
Your underlying problem is how to dynamically specify the type:
Dynamically specify the type in C#
Turns out that type casting (actually unboxing) in C# has very little overhead:
C# performance analysis- how to count CPU cycles?
Update:
Here is how you do the casting:
Dictionary<String,Object> parameters = new Dictionary<String,Object>();
// cast a string
parameters.Add("DatabaseName", "SomeBase");
// cast a list
parameters.Add("Classes", new List<int> { int.Parse("11"), int.Parse("12"), int.Parse("13") });
// cast an integer
parameters.Add("IntValue", int.Parse("3"));
// cast a double
parameters.Add("DoubleValue", Double.Parse("4.0"));
Then when you want to use the values you just do the unboxing:
int intValue = (int)parameters["IntValue"];
Double doubleValue = (Double)parameters["DoubleValue"];
List<int> classes = (List<int>)parameters["Classes"];
// etc...
As I mentioned before: after doing performance testing I found that unboxing has negligent overhead so you should not see any noticeable performance issues.
Update 2.0:
I'm guessing you want to automatically convert the type without having to explicitly specify it when you're adding it into the _settings dictionary. It should work if your dictionary's value is an Object:
Type t = typeof(double);
Object val = Convert.ChangeType("2.0", t);
// you still need to unbox the value to use it
double actual = (double)val;
So your example should work:
_settings[kVPair.Key] = Convert.ChangeType(value, type);
You just need to unbox the value with the correct type when you're going to use it.
You don't have to do this with generics.
You could simply have three methods like
public string GetStringConfig(string key){}
public List<int> GetListConfig(string key){}
public int GetIntegerConfig(string key){}
(you would have to throw an error if you try to parse / convert a string that does not match)
The above is like using a SQLAdapter.
This does of course assume you know the type of object the key should return

Categories

Resources