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
Related
I need to convert Dictionary to object that contain enum but I got error
error : cant cast enum and i cant fix it
private static T DictionaryToObject<T>(IDictionary<string, string> dict) where T : new()
{
var t = new T();
PropertyInfo[] properties = t.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
if (!dict.Any(x => x.Key.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase)))
continue;
KeyValuePair<string, string> item = dict.First(x => x.Key.Equals(property.Name, StringComparison.InvariantCultureIgnoreCase));
// Find which property type (int, string, double? etc) the CURRENT property is...
Type tPropertyType = t.GetType().GetProperty(property.Name).PropertyType;
// Fix nullables...
Type newT = Nullable.GetUnderlyingType(tPropertyType) ?? tPropertyType;
// ...and change the type
object newA = Convert.ChangeType(item.Value, newT);
t.GetType().GetProperty(property.Name).SetValue(t, newA, null);
}
return t;
}
I think you can convert a dictionary to a typed object by using a simpler way:
a Newtonsoft.Json NuGet package.
namespace MappingTest
{
using System;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
class Program
{
static void Main(string[] args)
{
var dict = new Dictionary<string, string>
{
{"TestProp1", "TestValue1"},
{"TestProp2", "TestValue2"}
};
var myClass = DictionaryToObject<MyClass>(dict);
Console.WriteLine($"myClass.TestProp1: {myClass.TestProp1}");
Console.WriteLine($"myClass.TestProp2: {myClass.TestProp2}");
}
enum TestValues
{
TestValue1,
TestValue2
}
class MyClass
{
public TestValues? TestProp1 { get; set; }
public TestValues TestProp2 { get; set; }
}
private static T DictionaryToObject<T>(IDictionary<string, string> dict)
{
JObject obj = JObject.FromObject(dict);
return obj.ToObject<T>();
}
}
}
I have the following code
Dictionary<string, string> changesDictionary = new Dictionary<string, string>();
if (changesDictionary.ContainsKey("field1"))
{
resultObject.field1 = changesDictionary["field1"];
}
if (changesDictionary.ContainsKey("field2"))
{
resultObject.field2 = changesDictionary["field2"];
}
if (changesDictionary.ContainsKey("field3"))
{
resultObject.field3 = changesDictionary["field3"];
}
which has 4 lines for a potential assignment. I'm wondering if there is a way to write it shorter.
I've tried the ternary operator which makes one line but it's harder to read.
resultObject.field1 = changesDictionary.ContainsKey("field1") ? changesDictionary["field1"] : resultObject.field1;
You could always do something like this. It's more verbose to start, but if you have lots of properties then it might pay off:
var fields = new (string key, Action<ResultObject, string> setter)[]
{
("field1", (x, val) => x.field1 = val),
("field2", (x, val) => x.field2 = val),
("field3", (x, val) => x.field3 = val),
};
foreach (var (key, setter) in fields)
{
if (changesDictionary.TryGetValue(key, out var field))
{
setter(resultObject, field);
}
}
Another option is something like this:
// A local function which captures 'resultObject' and 'changesDictionary'
void Set(string key, Action<ResultObject, string> setter)
{
if (changesDictionary.TryGetValue(key, out var field))
{
setter(resultObject, field);
}
}
Set("field1", (x, val) => x.field1 = val);
Set("field2", (x, val) => x.field2 = val);
Set("field3", (x, val) => x.field3 = val);
Otherwise, if you're prepared to change your style slightly, you can do this:
if (changesDictionary.TryGetValue("field1", out var field1)) resultObject.field1 = field1;
if (changesDictionary.TryGetValue("field2", out var field2)) resultObject.field2 = field2;
if (changesDictionary.TryGetValue("field3", out var field3)) resultObject.field1 = field3;
Using a local function:
void SetField(string fieldName, Action<string> updater)
{
if (changesDictionary.TryGetValue(fieldName, out string fieldValue))
{
updater(fieldValue);
}
}
SetField("field1", f => resultObject.field1 = f);
SetField("field2", f => resultObject.field2 = f);
SetField("field3", f => resultObject.field3 = f);
Price to pay = readability--
Line count = 11 instead of 13
Using a local function + reflection (provided fieldx are public properties):
void SetField(string fieldName)
{
if (changesDictionary.TryGetValue(fieldName, out string fieldValue))
{
PropertyInfo propertyInfo = resultObject.GetType().GetProperty(fieldName);
propertyInfo.SetValue(resultObject, fieldValue);
}
}
SetField("field1");
SetField("field2");
SetField("field3");
Price to pay = performance--
Line count = 12 instead of 13, but if you have 20 fields to update:
for (int i = 1; i <= 20; i++)
{
SetField($"field{i}");
}
Much shorter
Assuming (given the lowercase names for the field fields) that field1, field2 and field3 are actually fields rather than properties, then you can write a local function to simplify the code as follows:
Dictionary<string, string> changesDictionary = new Dictionary<string, string>();
void update(ref string field, string key)
{
if (changesDictionary.TryGetValue(key, out var value))
field = value;
}
update(ref resultObject.field1, "field1");
update(ref resultObject.field2, "field1");
update(ref resultObject.field3, "field1");
Note that will NOT work if field1 etc are actually properties, because of course you can't use ref with a property.
public static class DictionaryExtensions
{
public static TValue GetOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
{
if (dictionary.TryGetValue(key, out value))
return value;
return defaultValue;
}
}
. . .
resultObject.field1 = changesDictionary.GetOrDefault("field1", resultObject.field1);
resultObject.field2 = changesDictionary.GetOrDefault("field2", resultObject.field2);
resultObject.field3 = changesDictionary.GetOrDefault("field3", resultObject.field3);
If your object has FIELDS not PROPERTIES, u can use just TryGetValue to field like this
changesDictionary.TryGetValue(nameof(ResultObject.field1), out resultObject.field1);
full example:
using System;
using System.Collections.Generic;
namespace ConsoleApp27
{
internal class Program
{
private static void Main(string[] args)
{
var resultObject = new ResultObject();
var changesDictionary = new Dictionary<string, string>();
changesDictionary.Add(nameof(ResultObject.field1), "q1");
changesDictionary.Add(nameof(ResultObject.field2), "q2");
changesDictionary.Add(nameof(ResultObject.field3), "q3");
changesDictionary.Add(nameof(ResultObject.field4), "q4");
changesDictionary.TryGetValue(nameof(ResultObject.field1), out resultObject.field1);
changesDictionary.TryGetValue(nameof(ResultObject.field2), out resultObject.field2);
changesDictionary.TryGetValue(nameof(ResultObject.field3), out resultObject.field3);
changesDictionary.TryGetValue(nameof(ResultObject.field4), out resultObject.field4);
Console.WriteLine(resultObject.field1);
Console.WriteLine(resultObject.field2);
Console.WriteLine(resultObject.field3);
Console.WriteLine(resultObject.field4);
Console.ReadLine();
}
public class ResultObject
{
public string field1;
public string field2;
public string field3;
public string field4;
}
}
}
output:
q1
q2
q3
q4
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.
Having a model of type Dictionary<string,dynamic> and would like to convert it to Dictionary<string, MyType1> or Dictionary<string, MyOtherType>!
I've tried
var converted = (Dictionary<string,MyType1>)model
without success tried
IConvertible iConv = model; var converted = iConv.ToType(typeof(MyOtherType), null);
too but it doesn't work
Exception: Cannot convert system.object to type x
How do I convert from runtime type (dynamic) to a well known Type?
There is no built-in conversion from one dictionary type to another dictionary type. However, using Enumerable.ToDictionary, you can easily create a new dictionary from any other data structure.
In your particular example, you can use it as
var converted = model.ToDictionary(kv => kv.Key, kv => (MyType1) kv.Value);
Of course this will throw an exception if your values aren't actually of type MyType1. If they aren't, then instead of (MyType1) kv.Value, call some custom conversion function at that point.
The following little demo works for simple types:
MapDynamicToDictionary test shows turning the dynamic to a dictionary.
MapDictionaryToType shows converting the dictionary to a type T.
You could improve on this by doing checks for types or using as etc.
public class Test
{
[Fact]
public void MapDynamicToDictionary()
{
dynamic d = new { Nr = 1, Name = "Devon" };
var dictionary = TurnObjectIntoDictionary(d);
Assert.Equal(2, dictionary.Keys.Count);
}
[Fact]
public void MapDictionaryToType()
{
dynamic d = new { Nr = 1, Name = "Devon" };
var dictionary = TurnObjectIntoDictionary(d);
var instance = new MyType();
Map(dictionary, instance);
Assert.Equal(instance.Nr, 1);
Assert.Equal(instance.Name, "Devon");
}
public static void Map<T>(IDictionary<string, object> dictionary, T instance)
{
var attr = BindingFlags.Public | BindingFlags.Instance;
foreach (var prop in instance.GetType().GetProperties(attr))
{
if (prop.CanWrite)
{
if(dictionary.ContainsKey(prop.Name))
{
var v = Convert.ChangeType(dictionary[prop.Name], prop.PropertyType);
prop.SetValue(instance, v); }
}
}
}
public static IDictionary<string, object> TurnObjectIntoDictionary(object data)
{
var attr = BindingFlags.Public | BindingFlags.Instance;
var dict = new Dictionary<string, object>();
foreach (var prop in data.GetType().GetProperties(attr))
{
if (prop.CanRead)
{
dict.Add(prop.Name, prop.GetValue(data, null));
}
}
return dict;
}
}
class MyType
{
public int Nr { get; set; }
public string Name { get; set; }
}
Could use TypeConverter to handle more complex examples. Nice example here: http://putridparrot.com/blog/type-conversions-in-c/
I would put a static constructor on your well known type, which accepts dynamic, and build the well known type from that. e.g.
public class SomeType
{
public static SomeType FromDynamic(dynamic arg)
{
return new SomeType
{
SomeProperty = arg.SomeProp
}
}
public int SomeProperty {get; set; }
}
Then you'd just have to iterate over your Dictionary<string,dynamic> and build up the new object like:
var dictionary = new Dictionary<string, SomeType>();
foreach(var item in model)
{
dictionary.Add(item.Key, SomeType.FromDynamic(item.Value));
}
Or borrowing from #hvd:
var converted = model.ToDictionary(kv => kv.Key, kv => SomeType.FromDynamic(kv.Value));
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);