我有一个公共静态类Settings,我在其中存储了一些公共静态字段:
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" } };
}
}
现在我想将所有字段保存到文件中,但是可以添加新字段,而不需要保存和"手动"读取它们。
我决定使用我的动态和反射技能,并将所有字段列出到ExpandoObject,然后是JObject,然后是File。WriteAllText到settings.ini…难以置信,但它适用于所有的场类型,牛顿软件。Json可以序列化:
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());
}
但是现在我有一些麻烦阅读这个文本文件。我使用了标准的反射方法,只能读取数组和其他数据类型:
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));
}
}
}
我发现,牛顿软。Json还可以使用JsonConvert.DeserializeObject(object)对对象进行反序列化和强制转换为多种类型。我试过:
setting.SetValue(setting, JsonConvert.DeserializeObject<setting.FieldType>(obj[setting.Name].ToString()));
但是它给出了编译错误…你能帮我一下吗?
您想使用重载JsonConvert.DeserializeObject(String, Type)
:
setting.SetValue(setting, JsonConvert.DeserializeObject(obj[setting.Name].ToString(), setting.FieldType));
或者,您可以使用JToken.ToObject(Type)
,以避免不必要的转换为string:
setting.SetValue(setting, obj[setting.Name].ToObject(setting.FieldType));
并且,由于静态方法忽略了FieldInfo.SetValue(Object, Object)
的第一个Object
参数,因此为了清晰起见,您可能只想传递null:
setting.SetValue(null, obj[setting.Name].ToObject(setting.FieldType));
样本小提琴。
我不会把每个设置都标记为静态。相反,创建设置类的一个静态实例。例子:
public class Settings
{
public int appWidth = 800;
public int appHeight = 600;
public int layotCols = 1;
public int layotRows = 1;
public string TestString = "test";
public double TestFloat = 1.4;
public string[] TestStringArray = new[] { "1", "ee", "rrr"};
public List<string> TestStringArray1 = new List<string>() { "1", "2"};
public Dictionary<string,string> TestStringArray2 = new Dictionary<string, string> { { "key1", "value1" }, { "key2", "value2" } };
}
public static class App
{
public static Settings settings = new Settings();
}
你现在可以简单地用Json序列化/反序列化settings类。Net out of the box:
File.WriteAllText("settings.ini", JsonConvert.SerializeObject(App.settings));
JsonConvert.PopulateObject(File.ReadAllText("settings.ini"), App.settings);