Breket Breket - 9 months ago 85
JSON Question

Dynamic casting with JsonConvert.DeserializeObject<T> in static class in c#

I have a public static class Settings, where I store some public static fields:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.IO;
using System.Reflection;

namespace testApp {
public static class Settings {
public static int appWidth = 800;
public static int appHeight = 600;
public static int layotCols = 1;
public static int layotRows = 1;
public static string TestString = "test";
public static double TestFloat = 1.4;
public static string[] TestStringArray = new[] { "1", "ee", "rrr"};
public static List<string> TestStringArray1 = new List<string>() { "1", "2"};
public static Dictionary<string,string> TestStringArray2 = new Dictionary<string, string> { { "key1", "value1" }, { "key2", "value2" } };

Now I want to save all of the fields to the file, but with an ability to add new fields without the need to save and read them "manual".

I have decided to use my dynamic and reflection skills and to list all the fields to the ExpandoObject, then to JObject, and then File.WriteAllText to "settings.ini"...
Unbeliveable, but it works with all field types, that Newtonsoft.Json can serialize:

public static void saveSettings() {
Type type = typeof(Settings); // Settings is static class with static properties

dynamic dObject = new ExpandoObject();
var exObject = dObject as IDictionary<String, object>;

foreach(var setting in type.GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)) {
exObject[setting.Name] = Convert.ChangeType(setting.GetValue(null), setting.FieldType);

JObject obj = new JObject();
obj = JObject.FromObject(dObject);

File.WriteAllText("settings.ini", obj.ToString());

But now I have some troubles reading this text file.
I have used standart methods of reflection and can read only couple of datatypes but arrays and others:

public static void loadSettings() {
var settingsFile = File.ReadAllText("settings.ini");
JObject obj = JObject.Parse(settingsFile);

Type type = typeof(Settings);
foreach(var setting in type.GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)) {
if(obj[setting.Name]?.ToString() != null) {
setting.SetValue(setting, Convert.ChangeType(obj[setting.Name],setting.FieldType));

I found out, that Newtonsoft.Json can also deserialize and cast objects to many types with JsonConvert.DeserializeObject(object). I tried with:

setting.SetValue(setting, JsonConvert.DeserializeObject<setting.FieldType>(obj[setting.Name].ToString()));

But it gives compile Error... Can you help me please?

dbc dbc
Answer Source

You want to use the overload JsonConvert.DeserializeObject(String, Type):

setting.SetValue(setting, JsonConvert.DeserializeObject(obj[setting.Name].ToString(), setting.FieldType));

Alternatively, you could use JToken.ToObject(Type) and avoid the unnecessary conversion to string:

setting.SetValue(setting, obj[setting.Name].ToObject(setting.FieldType));

And, since the first Object argument to FieldInfo.SetValue(Object, Object) is ignored for static methods, you might want to just pass null for clarity:

setting.SetValue(null, obj[setting.Name].ToObject(setting.FieldType));

Sample fiddle.