数据类型序列化-封装

/// <summary>
/// 定义泛型接口
/// </summary>
/// <typeparam name="T">T</typeparam>
public interface ISettingValue<T>
{/// <summary>/// value/// </summary>T DoubleValue { get; }/// <summary>/// key/// </summary>string StringValue { get; }
}/// <summary>/// GenericSetting/// </summary>public abstract class GenericSetting : ISettingValue<double>{/// <summary>/// value[double]/// </summary>public abstract double DoubleValue { get; }/// <summary>/// value[string]/// </summary>public abstract string StringValue { get; }/// <summary>/// value[double[]]/// </summary>public abstract double[] DoubleValues { get; }/// <summary>/// value[double[][]]/// </summary>public abstract double[][] ArrayDoubleValues { get; }/// <summary>/// value[string[]]/// </summary>public abstract string[] StringValues { get; }/// <summary>/// 重写ToString方法,返回GenericSetting拼接json/// </summary>/// <returns></returns>public new abstract string ToString();/// <summary>/// abstract FromString/// </summary>/// <param name="info">string</param>/// <returns></returns>public abstract bool FromString(string info);public static implicit operator string(GenericSetting gs){Setting setting = gs as Setting;if (setting == null){throw new Exception("Not a Setting!");}if (setting.Strings == null && setting.Strings.Length != 0){throw new Exception("Setting has no Strings.");}return setting.Strings[0];}public static implicit operator string[](GenericSetting gs){Setting setting = gs as Setting;if (setting == null){return null;}if (setting.Strings == null){throw new Exception("Setting has no Strings.");}return setting.Strings;}public static implicit operator double(GenericSetting gs){Setting setting = gs as Setting;if (setting == null){throw new Exception("Not a Setting!");}if (setting.Values == null && setting.Values.Length != 0){throw new Exception("Setting has no Values.");}return setting.Values[0];}public static implicit operator int(GenericSetting gs){Setting setting = gs as Setting;if (setting == null){throw new Exception("Not a Setting!");}if (setting.Values == null && setting.Values.Length != 0){throw new Exception("Setting has no Values.");}return (int)setting.Values[0];}public static implicit operator int[](GenericSetting gs){Setting setting = gs as Setting;if (setting == null){return null;}if (setting.Values == null){throw new Exception("Setting has no Values.");}double[] values = setting.Values;int[] array = new int[values.Length];for (int i = 0; i < array.Length; i++){array[i] = (int)values[i];}return array;}public static implicit operator double[](GenericSetting gs){Setting setting = gs as Setting;if (setting == null){return null;}if (setting.Values == null){throw new Exception("Setting has no Values.");}return setting.Values;}public static implicit operator double[][](GenericSetting gs){Setting setting = gs as Setting;if (setting == null){return null;}if (setting.Values == null){throw new Exception("Setting has no Values.");}return setting.ArrayValues;}public static implicit operator GenericSetting(double val){Setting setting = new Setting();setting.Values = new double[1] { val };setting.Strings = new string[0];return setting;}public static implicit operator GenericSetting(string val){Setting setting = new Setting();setting.Values = new double[0];setting.Strings = new string[1] { val };return setting;}public static implicit operator GenericSetting(string[] vals){Setting setting = new Setting();if (vals == null){return setting;}string[] array = new string[vals.Length];for (int i = 0; i < vals.Length; i++){array[i] = vals[i];}setting.Strings = array;setting.Values = new double[0];return setting;}public static implicit operator GenericSetting(double[] vals){Setting setting = new Setting();if (vals == null){return setting;}double[] array = new double[vals.Length];for (int i = 0; i < vals.Length; i++){array[i] = vals[i];}setting.Values = array;setting.Strings = new string[0];return setting;}public static implicit operator GenericSetting(double[][] arrayVals){Setting setting = new Setting();if (arrayVals == null){return setting;}setting.Values = new double[0];setting.Strings = new string[0];setting.ArrayValues = arrayVals;return setting;}/// <summary>/// Initializes a new instance of the <see cref="GenericSetting"/> class./// </summary>protected GenericSetting(){}}/// <summary>/// Setting/// </summary>[Serializable]public class Setting : GenericSetting, ISerializable{/// <summary>/// 附件信息/// </summary>protected Dictionary<string, string> otherInfo;/// <summary>/// double[]/// </summary>protected double[] iVal;/// <summary>/// double[][]/// </summary>protected double[][] iArrayVal;/// <summary>/// string[]/// </summary>protected string[] iStr;/// <summary>/// 时间戳/// </summary>public string TimeStamp => otherInfo["SettingTimeStamp"];/// <summary>/// 协议版本【暂未使用】/// </summary>public int Version => int.Parse(otherInfo["SettingVersion"]);/// <summary>/// Unit/// </summary>public string Units{get{if (otherInfo.ContainsKey("SettingUnits")){return otherInfo["SettingUnits"];}return "NotExist";}}/// <summary>/// 附加信息/// </summary>public Dictionary<string, string> OtherInfo{get{if (otherInfo == null){otherInfo = new Dictionary<string, string>();}return otherInfo;}set{otherInfo = value;}}/// <summary>/// double[]/// </summary>public double[] Values{get{return iVal;}set{iVal = value;OtherInfo["SettingTimeStamp"] = DateTime.Now.ToString("yyyy-M-d tt H:mm:ss.ffffff", CultureInfo.InvariantCulture);OtherInfo["SettingVersion"] = VersionInfo.GetVersion().ToString();}}/// <summary>/// double[][]/// </summary>public double[][] ArrayValues{get{return iArrayVal;}set{iArrayVal = value;OtherInfo["SettingTimeStamp"] = DateTime.Now.ToString("yyyy-M-d tt H:mm:ss.ffffff", CultureInfo.InvariantCulture);OtherInfo["SettingVersion"] = VersionInfo.GetVersion().ToString();}}/// <summary>/// string[]/// </summary>public string[] Strings{get{return iStr;}set{iStr = value;OtherInfo["SettingTimeStamp"] = DateTime.Now.ToString("yyyy-M-d tt H:mm:ss.ffffff", CultureInfo.InvariantCulture);OtherInfo["SettingVersion"] = VersionInfo.GetVersion().ToString();}}/// <summary>/// 获取附件信息/// </summary>/// <param name="key">附加信息key</param>/// <returns></returns>public string this[string key]{get{return otherInfo[key];}set{otherInfo[key] = value;}}/// <summary>/// Initializes a new instance of the <see cref="Setting"/> class./// </summary>public Setting(){otherInfo = new Dictionary<string, string>();iVal = new double[0];iStr = new string[0];iArrayVal = new double[0][];}/// <summary>/// Initializes a new instance of the <see cref="Setting"/> class./// </summary>/// <param name="gs">GenericSetting</param>public Setting(GenericSetting gs){Setting setting = gs as Setting;if (setting == null){throw new Exception("Not a Setting!");}iVal = new double[setting.iVal.Length];setting.iVal.CopyTo(iVal, 0);iStr = new string[setting.iStr.Length];setting.iStr.CopyTo(iStr, 0);otherInfo = new Dictionary<string, string>();string[] array = setting.otherInfo.Keys.ToArray();foreach (string key in array){otherInfo[key] = setting.otherInfo[key];}}/// <summary>/// Initializes a new instance of the <see cref="Setting"/> class. /// </summary>/// <param name="old">Copy</param>public Setting(Setting old){iVal = new double[old.iVal.Length];old.iVal.CopyTo(iVal, 0);iStr = new string[old.iStr.Length];old.iStr.CopyTo(iStr, 0);otherInfo = new Dictionary<string, string>();string[] array = old.otherInfo.Keys.ToArray();foreach (string key in array){otherInfo[key] = old.otherInfo[key];}}public static implicit operator Setting(double val){Setting setting = new Setting();setting.Values = new double[1] { val };setting.Strings = new string[0];return setting;}public static implicit operator Setting(string val){Setting setting = new Setting();setting.Values = new double[0];setting.Strings = new string[1] { val };return setting;}public static implicit operator Setting(string[] vals){Setting setting = new Setting();string[] array = new string[vals.Length];for (int i = 0; i < vals.Length; i++){array[i] = vals[i];}setting.Strings = array;setting.Values = new double[0];return setting;}public static implicit operator Setting(double[] vals){Setting setting = new Setting();double[] array = new double[vals.Length];for (int i = 0; i < vals.Length; i++){array[i] = vals[i];}setting.Values = array;setting.Strings = new string[0];return setting;}public static implicit operator Setting(double[][] vals){Setting setting = new Setting();setting.Values = new double[0];setting.Strings = new string[0];setting.ArrayValues = vals;return setting;}/// <summary>/// SettingTimeStamp to DateTime/// </summary>/// <returns></returns>public DateTime GetTimeStamp(){return DateTime.Parse(OtherInfo["SettingTimeStamp"], CultureInfo.InvariantCulture);}public string[] getOtherInfoKeys(){List<string> list = OtherInfo.Keys.ToList();list.Sort();return list.ToArray();}public string[] getOtherInfoStrings(){Dictionary<string, string> dictionary = OtherInfo;List<string> list = dictionary.Keys.ToList();list.Sort();string[] array = new string[list.Count];for (int i = 0; i < array.Length; i++){array[i] = dictionary[list[i]];}return array;}/// <summary>/// override ToString/// </summary>/// <returns></returns>public override string ToString(){return ToString();}/// <summary>/// ToString with level/// </summary>/// <param name="level">string</param>/// <returns></returns>public string ToString(string level = ""){string text = "{\n" + level + "\t\"OtherInfo\": {\n";bool flag = true;List<string> list = otherInfo.Keys.ToList();list.Sort();foreach (string item in list){if (flag){flag = false;}else{text += ",\n";}text = text + level + "\t\t\"" + item + "\":\"" + otherInfo[item] + "\"";}text = text + "\n" + level + "\t},\n";text = text + level + "\t\"Values\": [";string text2 = "";for (int i = 0; i < iVal.Length; i++){text = (!double.IsPositiveInfinity(iVal[i])) ? ((!double.IsNegativeInfinity(iVal[i])) ? ((!double.IsNaN(iVal[i])) ? (text + text2 + iVal[i]) : (text + text2 + "NaN")) : (text + text2 + "-Infinity")) : (text + text2 + "Infinity");text2 = ",";}text += "],\n";text = text + level + "\t\"Strings\": [";text2 = "";for (int j = 0; j < iStr.Length; j++){text = text + text2 + "\"" + iStr[j].Replace("\\", "\\\\") + "\"";text2 = ",";}return text + "]\n" + level + "}";}/// <summary>/// FromString/// </summary>/// <param name="info">string</param>/// <returns></returns>public override bool FromString(string info){try{string text = "\"OtherInfo\": {";int num = info.IndexOf(text) + text.Length;int num2 = info.IndexOf("}", num);string text2 = info.Substring(num, num2 - num);List<string> list = new List<string>();while (text2.Contains("\"")){int num3 = text2.IndexOf("\"");int num4 = text2.IndexOf("\"", num3 + 1);list.Add(text2.Substring(num3 + 1, num4 - num3 - 1));text2 = text2.Substring(num4 + 1);}for (int i = 0; i < list.Count; i += 2){otherInfo[list[i]] = list[i + 1];}text = "\"Values\": [";int num5 = info.IndexOf(text) + text.Length;int num6 = info.IndexOf("]", num5);string text3 = info.Substring(num5, num6 - num5);List<string> list2 = new List<string>();while (text3.Contains(",")){int num7 = text3.IndexOf(",");if (num7 == -1){break;}list2.Add(text3.Substring(0, num7));text3 = text3.Substring(num7 + 1);}if (text3 != ""){list2.Add(text3);}iVal = new double[list2.Count];for (int j = 0; j < list2.Count; j++){if (!double.TryParse(list2[j], out iVal[j])){if (list2[j] == "Infinity"){iVal[j] = double.PositiveInfinity;}else if (list2[j] == "-Infinity"){iVal[j] = double.NegativeInfinity;}else{iVal[j] = double.NaN;}}}text = "\"Strings\": [";num5 = info.IndexOf(text) + text.Length;num6 = info.IndexOf("]", num5);text3 = info.Substring(num5, num6 - num5);list2 = new List<string>();while (text3.Contains(",")){int num8 = text3.IndexOf(",");if (num8 == -1){break;}list2.Add(text3.Substring(0, num8));text3 = text3.Substring(num8 + 1);}if (text3 != ""){list2.Add(text3);}iStr = new string[list2.Count];for (int k = 0; k < list2.Count; k++){iStr[k] = list2[k].Substring(1, list2[k].Length - 2).Replace("\\\\", "\\");if (iStr[k].Contains("\"")){iStr[k] = iStr[k].Substring(iStr[k].IndexOf("\"") + 1);if (iStr[k].Contains("\"")){iStr[k] = iStr[k].Substring(0, iStr[k].LastIndexOf("\""));}}}}catch{return false;}return true;}/// <summary>/// Initializes a new instance of the <see cref="Setting"/> class.  反序列化构造方法[实现反序列化]/// </summary>/// <param name="info">SerializationInfo</param>/// <param name="context">StreamingContext</param>protected Setting(SerializationInfo info, StreamingContext context){otherInfo = new Dictionary<string, string>();string[] array = info.GetValue("otherInfoKeys", typeof(string[])) as string[];string[] array2 = info.GetValue("otherInfoValues", typeof(string[])) as string[];for (int i = 0; i < array.Length; i++){otherInfo[array[i]] = array2[i];}iVal = info.GetValue("iVal", typeof(double[])) as double[];iStr = info.GetValue("iStr", typeof(string[])) as string[];iArrayVal = info.GetValue("iArrayVal", typeof(double[][])) as double[][];}/// <summary>/// 序列化方法/// </summary>/// <param name="info">SerializationInfo</param>/// <param name="context">StreamingContext</param>public virtual void GetObjectData(SerializationInfo info, StreamingContext context){info.AddValue("iStr", iStr);info.AddValue("iVal", iVal);info.AddValue("iArrayVal", iArrayVal);info.AddValue("otherInfoKeys", otherInfo.Keys.ToArray());info.AddValue("otherInfoValues", otherInfo.Values.ToArray());}/// <summary>/// double/// </summary>public override double DoubleValue => Values?.Length > 0 ? Values[0] : default;/// <summary>/// string/// </summary>public override string StringValue => Strings?.Length > 0 ? Strings[0] : default;/// <summary>/// double[]/// </summary>public override double[] DoubleValues => Values;/// <summary>/// string[]/// </summary>public override string[] StringValues => Strings;/// <summary>/// double[][]/// </summary>public override double[][] ArrayDoubleValues => ArrayValues;}[Serializable]public class SettingContainer : Setting, ISerializable{public Dictionary<string, SettingContainer> SettingsContainers;public Dictionary<string, Setting> Settings;private static string delimiter;private static List<string> m_OtherInfoKeys;[NonSerialized]private string[] skeys;[NonSerialized]private Setting[] sValues;[NonSerialized]private string[] sckeys;[NonSerialized]private SettingContainer[] scValues;[NonSerialized]private bool isDeserialized;/// <summary>/// split "."/// </summary>public static string Delimiter => delimiter;/// <summary>/// get/set value with key/// </summary>/// <param name="key">string</param>/// <returns></returns>public GenericSetting this[string key]{get{int num = key.IndexOf(delimiter);if (num > 0){string text = key.Substring(0, num);string text2 = key.Substring(num + 1);SettingContainer settingContainer = null;if (SettingsContainers != null && SettingsContainers.ContainsKey(text)){settingContainer = SettingsContainers[text];try{return settingContainer[text2];}catch (Exception innerException){throw new Exception("Can not find key " + key + " (failed in" + text2 + ")", innerException);}}throw new Exception("Can not find key " + key + " (missing " + text + ")");}if (Settings != null && Settings.ContainsKey(key)){return Settings[key];}if (SettingsContainers == null || !SettingsContainers.ContainsKey(key)){throw new Exception("Can't find key " + key);}return SettingsContainers[key];}set{int num = key.IndexOf(delimiter);if (num > 0){string key2 = key.Substring(0, num);string key3 = key.Substring(num + 1);if (SettingsContainers == null){SettingsContainers = new Dictionary<string, SettingContainer>();}if (!SettingsContainers.ContainsKey(key2)){SettingsContainers[key2] = new SettingContainer();}SettingsContainers[key2][key3] = value;}else if (value is Setting){if (Settings == null){Settings = new Dictionary<string, Setting>();}Settings[key] = value as Setting;}else if (value is SettingContainer){if (SettingsContainers == null){SettingsContainers = new Dictionary<string, SettingContainer>();}SettingsContainers[key] = value as SettingContainer;}else{if (value != null){throw new Exception("value can not be set into " + key);}if (Settings != null && Settings.ContainsKey(key)){Settings.Remove(key);}if (SettingsContainers != null && SettingsContainers.ContainsKey(key)){SettingsContainers.Remove(key);}}}}/// <summary>/// Initializes a new instance of the <see cref="SettingContainer"/> class. /// </summary>public SettingContainer(){}/// <summary>/// Initializes a new instance of the <see cref="SettingContainer"/> class./// </summary>/// <param name="old">SettingContainer</param>public SettingContainer(SettingContainer old){if (old.SettingsContainers != null){SettingsContainers = new Dictionary<string, SettingContainer>();string[] array = old.SettingsContainers.Keys.ToArray();foreach (string key in array){SettingsContainers[key] = new SettingContainer(old.SettingsContainers[key]);}}if (old.Settings != null){Settings = new Dictionary<string, Setting>();string[] array = old.Settings.Keys.ToArray();foreach (string key2 in array){Settings[key2] = new Setting(old.Settings[key2]);}}}public static implicit operator SettingContainer(Dictionary<string, double[]> dictionarySettings){SettingContainer settingContainer = new SettingContainer();settingContainer.updateSettings(dictionarySettings);return settingContainer;}public static implicit operator SettingContainer(Dictionary<string, string[]> dictionarySettings){SettingContainer settingContainer = new SettingContainer();settingContainer.updateStringSettings(dictionarySettings);return settingContainer;}public static implicit operator Dictionary<string, double[]>(SettingContainer gs){return gs.GetDictionary();}public static implicit operator Dictionary<string, string[]>(SettingContainer gs){return gs.GetStringDictionary();}/// <summary>/// ContainsKey/// </summary>/// <param name="key">string</param>/// <returns>bool</returns>public bool ContainsKey(string key){return Keys().Contains(key);}/// <summary>/// get keys/// </summary>/// <param name="superKey">superKey</param>/// <returns>List<string></returns>public List<string> Keys(string superKey = ""){List<string> list = new List<string>();if (SettingsContainers != null){foreach (string key in SettingsContainers.Keys){foreach (string item in SettingsContainers[key].Keys(superKey + key + ".")){list.Add(item);}}}if (Settings != null){foreach (string key2 in Settings.Keys){list.Add(superKey + key2);}return list;}return list;}public GenericSetting NullableGet(string key){int num = key.IndexOf(delimiter);if (num > 0){string key2 = key.Substring(0, num);string key3 = key.Substring(num + 1);if (SettingsContainers != null && SettingsContainers.ContainsKey(key2)){return SettingsContainers[key2]?.NullableGet(key3);}return null;}if (Settings != null && Settings.ContainsKey(key)){return Settings[key];}if (SettingsContainers != null){if (SettingsContainers.ContainsKey(key)){return SettingsContainers[key];}return null;}return null;}public Dictionary<string, Setting> GetSettingDictionary(){Dictionary<string, Setting> dictionary = new Dictionary<string, Setting>();if (Settings != null){foreach (string key in Settings.Keys){dictionary[key] = Settings[key];}}Dictionary<string, SettingContainer> dictionary2 = null;bool flag;if (flag = SettingsContainers != null){dictionary2 = SettingsContainers;}while (flag){Dictionary<string, SettingContainer> dictionary3 = new Dictionary<string, SettingContainer>();new List<SettingContainer>();foreach (string key2 in dictionary2.Keys){SettingContainer settingContainer = dictionary2[key2];if (settingContainer.SettingsContainers != null){foreach (string key3 in settingContainer.SettingsContainers.Keys){dictionary3[key2 + delimiter + key3] = settingContainer.SettingsContainers[key3];}}if (settingContainer.Settings == null){continue;}foreach (string item in settingContainer.Settings.Keys.ToList()){dictionary[key2 + delimiter + item] = settingContainer.Settings[item];}}dictionary2 = dictionary3;flag = dictionary2.Count > 0;}return dictionary;}public Dictionary<string, double[]> GetDictionary(){Dictionary<string, double[]> dictionary = new Dictionary<string, double[]>();Dictionary<string, Setting> settingDictionary = GetSettingDictionary();foreach (string key in settingDictionary.Keys){if (settingDictionary[key].Values.Length != 0){dictionary[key] = new double[settingDictionary[key].Values.Length];settingDictionary[key].Values.CopyTo(dictionary[key], 0);}}return dictionary;}public Dictionary<string, string[]> GetStringDictionary(bool withOtherInfo = true){Dictionary<string, string[]> dictionary = new Dictionary<string, string[]>();Dictionary<string, Setting> settingDictionary = GetSettingDictionary();foreach (string key in settingDictionary.Keys){if (withOtherInfo){foreach (string key2 in settingDictionary[key].OtherInfo.Keys){dictionary[key + delimiter + key2] = new string[1] { settingDictionary[key].OtherInfo[key2] };}}if (settingDictionary[key].Strings.Length != 0){dictionary[key] = new string[settingDictionary[key].Strings.Length];settingDictionary[key].Strings.CopyTo(dictionary[key], 0);}}return dictionary;}public void updateSettings(Dictionary<string, double[]> DictionarySettings){Dictionary<string, Setting> settingDictionary = GetSettingDictionary();foreach (string key in DictionarySettings.Keys){try{Setting setting = null;setting = (Setting)(settingDictionary.ContainsKey(key) ? settingDictionary[key] : (this[key] = new Setting()));setting.Values = DictionarySettings[key].ToArray();}catch (Exception innerException){throw new Exception("Error with key " + key, innerException);}}}public void updateStringSettings(Dictionary<string, string[]> DictionarySettings){Dictionary<string, Setting> settingDictionary = GetSettingDictionary();foreach (string key in DictionarySettings.Keys){string text = null;string text2 = null;try{int num = key.LastIndexOf(delimiter);if (num > 0){text = key.Substring(num + 1);}if (m_OtherInfoKeys.Contains(text)){text2 = key.Substring(0, num);}else{text = null;text2 = key;}Setting setting = null;setting = (Setting)(settingDictionary.ContainsKey(text2) ? settingDictionary[text2] : (this[text2] = (settingDictionary[text2] = new Setting())));if (text == null){string[] source = DictionarySettings[text2];setting.Strings = source.ToArray();}else if (DictionarySettings[key].Length != 0){setting.OtherInfo[text] = DictionarySettings[key][0];}}catch{throw;}}}/// <summary>/// Initializes a new instance of the <see cref="SettingContainer"/> class.  反序列化构造方法[实现反序列化]/// </summary>/// <param name="info">SerializationInfo</param>/// <param name="context">StreamingContext</param>protected SettingContainer(SerializationInfo info, StreamingContext context){skeys = info.GetValue("DictionarySettingsKeys", typeof(string[])) as string[];sValues = info.GetValue("DictionarySettingsValues", typeof(Setting[])) as Setting[];sckeys = info.GetValue("DictionarySettingContainersKeys", typeof(string[])) as string[];scValues = info.GetValue("DictionarySettingContainersValues", typeof(SettingContainer[])) as SettingContainer[];}/// <summary>/// 序列化方法/// </summary>/// <param name="info">SerializationInfo</param>/// <param name="context">StreamingContext</param>public virtual void GetObjectData(SerializationInfo info, StreamingContext context){if (Settings != null){info.AddValue("DictionarySettingsKeys", Settings.Keys.ToArray());info.AddValue("DictionarySettingsValues", Settings.Values.ToArray());}else{info.AddValue("DictionarySettingsKeys", null);info.AddValue("DictionarySettingsValues", null);}if (SettingsContainers != null){info.AddValue("DictionarySettingContainersKeys", SettingsContainers.Keys.ToArray());info.AddValue("DictionarySettingContainersValues", SettingsContainers.Values.ToArray());}else{info.AddValue("DictionarySettingContainersKeys", null);info.AddValue("DictionarySettingContainersValues", null);}}[OnDeserialized]internal void OnDeserialized(StreamingContext context){if (skeys != null){Settings = new Dictionary<string, Setting>();for (int i = 0; i < skeys.Length; i++){Settings[skeys[i]] = sValues[i];}skeys = null;sValues = null;}if (sckeys != null){SettingsContainers = new Dictionary<string, SettingContainer>();for (int j = 0; j < sckeys.Length; j++){SettingsContainers[sckeys[j]] = scValues[j];}sckeys = null;scValues = null;}isDeserialized = true;}public override string ToString(){return ToString("");}public string ToString(string level){string text = "{\n";bool flag = true;if (SettingsContainers != null){text = text + level + "\t\"SettingsContainers\": {\n";List<string> list = SettingsContainers.Keys.ToList();list.Sort();foreach (string item in list){if (flag){flag = false;}else{text += ",\n";}text = text + level + "\t\t\"" + item + "\": ";text += SettingsContainers[item].ToString(level + "\t\t");}text = text + "\n\t" + level + "},\n";}else{text = text + level + "\t\"SettingsContainers\": null,\n";}flag = true;if (Settings != null){text = text + level + "\t\"Settings\": {\n";List<string> list2 = Settings.Keys.ToList();list2.Sort();foreach (string item2 in list2){if (flag){flag = false;}else{text += ",\n";}text = text + level + "\t\t\"" + item2 + "\": ";text += Settings[item2].ToString(level + "\t\t");}text = text + "\n" + level + "\t}\n";}else{text = text + level + "\t\"Settings\": null\n";}return text + level + "}";}public override bool FromString(string info){return FromString2(info, "");}private bool FromString2(string info, string settingOrContainer){try{if (settingOrContainer == "settings"){SettingsContainers = null;Settings = new Dictionary<string, Setting>();}if (settingOrContainer == "SettingsContainers"){SettingsContainers = new Dictionary<string, SettingContainer>();Settings = null;}int num = 0;while (num > -1 && num < info.Length){int num2 = info.IndexOf("\"", num);if (num2 < 0){break;}int num3 = info.IndexOf("\"", num2 + 1);string text = info.Substring(num2 + 1, num3 - num2 - 1);int num4 = info.IndexOf("{", num3 + 1);int num5 = num4;int num6 = 1;int num7 = 0;int num8 = info.IndexOf(",", num3 + 1);if (num8 < num4){num = num8;continue;}if (num4 < 0){break;}while (num7 < num6){int num9 = info.IndexOf("{", num5 + 1);int num10 = info.IndexOf("}", num5 + 1);if (num9 < 0){num9 = info.Length;}if (num10 < 0){break;}if (num9 < num10){num6++;num5 = num9;}else{num7++;num5 = num10;}}string info2 = info.Substring(num4, num5 - num4 + 1);if (text == "Settings"){settingOrContainer = "settings";SettingContainer settingContainer = new SettingContainer();try{settingContainer.FromString2(info2, settingOrContainer);}catch{settingContainer = null;}Settings = settingContainer.Settings;}else if (settingOrContainer == "settings"){Setting setting = new Setting();try{setting.FromString(info2);}catch{setting = null;}Settings[text] = setting;}else if (text == "SettingsContainers"){settingOrContainer = "SettingsContainers";SettingContainer settingContainer2 = new SettingContainer();try{settingContainer2.FromString2(info2, settingOrContainer);}catch{settingContainer2 = null;}SettingsContainers = settingContainer2.SettingsContainers;}else if (settingOrContainer == "SettingsContainers"){SettingContainer settingContainer3 = new SettingContainer();try{settingContainer3.FromString(info2);}catch{settingContainer3 = null;}SettingsContainers[text] = settingContainer3;}num = num5 + 1;}}catch{return false;}return true;}public Dictionary<string, string> compare(SettingContainer other, bool swap = true, double tolerance = 0.0){Dictionary<string, string> dictionary = (!swap) ? new Dictionary<string, string>() : other.compare(this, swap: false);Dictionary<string, double[]> dictionary2 = GetDictionary();Dictionary<string, string[]> stringDictionary = GetStringDictionary();Dictionary<string, double[]> dictionary3 = other.GetDictionary();Dictionary<string, string[]> stringDictionary2 = other.GetStringDictionary();foreach (string key in dictionary2.Keys){double[] array = dictionary2[key];if (!dictionary3.ContainsKey(key)){dictionary[key] = "missing key";continue;}double[] array2 = dictionary3[key];if (array.Length != array2.Length){dictionary[key] = "mismatched size";continue;}for (int i = 0; i < array.Length; i++){if (double.IsNaN(array[i]) != double.IsNaN(array2[i]) && Math.Abs(array[i] - array2[i]) <= tolerance){dictionary[key + ";" + i] = "mismatched value " + array[i] + " != " + array2[i];}}}foreach (string key2 in stringDictionary.Keys){if (key2.Contains("SettingTimeStamp") || key2.Contains("AcuShape.PROCESSING.version")){continue;}if (!stringDictionary2.ContainsKey(key2)){dictionary[key2] = "missing key";continue;}if (stringDictionary[key2].Length != stringDictionary2[key2].Length){dictionary[key2] = "mismatched size";continue;}for (int j = 0; j < stringDictionary[key2].Length; j++){if (stringDictionary[key2][j] != stringDictionary2[key2][j]){dictionary[key2 + ";" + j] = "mismatched value";}}}return dictionary;}static SettingContainer(){delimiter = ".";m_OtherInfoKeys = new List<string> { "SettingTimeStamp", "SettingUnits", "SettingVersion" };}}public class VersionInfo{public const string Version = "1.0.0.0";public static string GetVersion(){return Version;}public VersionInfo(){}}

配置数据管理体系:ISettingValue<T>GenericSettingSetting 与 SettingContainer 解析

一、体系整体定位与核心功能

该代码片段构建了一套标准化的配置数据管理体系,核心用于工业控制、设备参数配置或系统设置等场景中,实现 “多类型数据统一存储、序列化 / 反序列化、灵活访问” 的需求。整个体系通过 “接口 - 抽象类 - 具体类 - 容器类” 的层级设计,覆盖了从单一配置项到复杂嵌套配置的全场景,支持 doublestring 及多维数组类型,并提供 JSON 格式转换、序列化、数据对比等核心能力。

二、核心组件与层级关系

整个体系的层级结构清晰,各组件职责单一且协同配合,具体关系如下:

ISettingValue 泛型接口

GenericSetting 抽象类

Setting 具体配置类

SettingContainer 配置容器类

嵌套存储 Setting/SettingContainer

各组件的核心定位:

  • ISettingValue<T>:定义配置项的基础访问接口,约束 “值(DoubleValue)” 和 “键(StringValue)” 的获取方式。
  • GenericSetting:抽象基类,扩展接口能力,支持多维数据(double[]/double[][]/string[]),并提供隐式类型转换(如 GenericSetting 与 double/string/ 数组的互转)。
  • Setting:具体配置实现类,支持序列化(ISerializable)、JSON 格式转换(ToString/FromString),并存储配置的附加信息(时间戳、版本、单位等)。
  • SettingContainer:配置容器类,基于字典结构存储多个 Setting 或嵌套 SettingContainer,支持 “键路径访问”(如 container["parent.child.key"]),解决复杂嵌套配置的管理问题。

三、核心组件详解

1. 泛型接口:ISettingValue<T>

核心作用

定义配置项的最小功能契约,约束所有配置类必须实现 “值” 和 “键” 的获取逻辑,其中 T 默认为 double(由 GenericSetting 实现时指定)。

关键成员
成员类型作用说明
DoubleValueTdouble获取配置的数值型值(核心数据)
StringValuestring获取配置的字符串型键 / 描述(标识)
设计意义

通过接口标准化配置项的访问方式,确保不同配置类的一致性,便于后续扩展和统一管理。

2. 抽象基类:GenericSetting

核心作用

作为 ISettingValue<double> 的实现者和 Setting 的基类,扩展多维数据支持和类型转换能力,是整个体系的 “功能中转站”。

关键成员与能力
(1)多维数据访问(抽象属性)

定义了覆盖单值、一维数组、二维数组的抽象属性,强制子类(Setting)实现数据存储逻辑:

  • DoubleValue:单值 double(实现接口)
  • StringValue:单值 string(实现接口)
  • DoubleValuesdouble[](一维数值数组)
  • ArrayDoubleValuesdouble[][](二维数值数组)
  • StringValuesstring[](一维字符串数组)
(2)隐式类型转换(核心亮点)

提供 11 种隐式转换,支持 GenericSetting 与常见类型的无缝互转,极大简化代码编写。例如:

  • GenericSetting → double:直接获取配置的第一个数值(Values[0]
  • double → GenericSetting:将单值 double 封装为 Setting 对象
  • string[] → GenericSetting:将字符串数组封装为 Setting 对象
  • GenericSetting → double[][]:直接获取二维数值数组(ArrayValues

转换示例代码

csharp

// double 隐式转为 GenericSetting
GenericSetting gs1 = 123.45; 
Console.WriteLine(gs1.DoubleValue); // 输出 123.45// string[] 隐式转为 GenericSetting
GenericSetting gs2 = new string[] { "name", "age" };
Console.WriteLine(gs2.StringValues[1]); // 输出 "age"// GenericSetting 隐式转为 double[]
double[] values = gs1; 
Console.WriteLine(values[0]); // 输出 123.45
(3)序列化基础方法

定义抽象方法 ToString()(JSON 序列化)和 FromString(string info)(JSON 反序列化),强制子类实现数据与字符串的转换逻辑。

3. 具体配置类:Setting

核心作用

GenericSetting 的具体实现,是 “单一配置项” 的最终载体,支持序列化、附加信息存储、JSON 解析,是体系中最常用的基础配置单元。

关键成员与能力
(1)核心数据存储字段
字段类型作用说明
iValdouble[]存储数值型数据(对应 DoubleValues
iArrayValdouble[][]存储二维数值型数据(对应 ArrayDoubleValues
iStrstring[]存储字符串型数据(对应 StringValues
otherInfoDictionary<string, string>存储附加信息(时间戳、版本、单位等)
(2)附加信息管理(实用功能)

通过 otherInfo 字典存储配置的元数据,提供便捷访问属性:

  • TimeStamp:配置更新时间戳(格式:yyyy-M-d tt H:mm:ss.ffffff
  • Version:配置版本(来自 VersionInfo,默认 1.0.0.0
  • Units:数据单位(如 “℃”“m/s”,默认 “NotExist”)
  • 索引器 this[string key]:直接访问附加信息(如 setting["SettingUnits"]
(3)JSON 序列化 / 反序列化(核心功能)
  • ToString(string level = ""):将配置数据(含附加信息、数值、字符串)转换为格式化 JSON 字符串,支持缩进(level 参数控制缩进层级),便于人类阅读和日志记录。
    • 示例输出:

      json

      {"OtherInfo": {"SettingTimeStamp":"2024-5-20 PM 3:30:45.123456","SettingVersion":"1.0.0.0","SettingUnits":"℃"},"Values": [25.5, 26.1],"Strings": ["Temperature1", "Temperature2"]
      }
      
  • FromString(string info):从 JSON 字符串解析配置数据,自动填充 iValiStrotherInfo,支持异常处理(解析失败返回 false)。
(4)序列化支持(ISerializable

实现 .NET 序列化接口,支持跨进程 / 跨平台数据传输,通过 GetObjectData 方法将核心字段(iValiStriArrayValotherInfo)写入序列化流,反序列化时通过构造函数恢复数据。

4. 配置容器类:SettingContainer

核心作用

管理多个 Setting 或嵌套 SettingContainer,解决 “复杂配置场景”(如层级化系统设置、多设备参数集合)的存储和访问问题,相当于 “配置的字典容器”。

关键成员与能力
(1)核心存储结构
字段类型作用说明
SettingsDictionary<string, Setting>存储单一配置项(键 -Setting 映射)
SettingsContainersDictionary<string, SettingContainer>存储嵌套容器(键 -SettingContainer 映射)
delimiterstring(静态)键路径分隔符(默认 “.”),用于层级访问
(2)层级化键访问(核心亮点)

通过 索引器 this[string key] 支持 “点分隔符” 的层级化访问,无需手动逐层获取嵌套容器,极大简化代码。例如:

  • 访问嵌套配置:container["Device1.Temperature.SetPoint"],自动解析为 container → SettingsContainers["Device1"] → SettingsContainers["Temperature"] → Settings["SetPoint"]
  • 赋值嵌套配置:container["Device1.Temperature.SetPoint"] = 25.0,自动创建不存在的中间容器。

示例代码

csharp

// 创建容器并添加嵌套配置
SettingContainer container = new SettingContainer();
// 直接赋值层级化配置(自动创建中间容器 Device1 和 Temperature)
container["Device1.Temperature.SetPoint"] = 25.0; 
container["Device1.Temperature.Unit"] = "℃";// 直接访问层级化配置
double setPoint = (double)container["Device1.Temperature.SetPoint"];
string unit = (string)container["Device1.Temperature.Unit"];
Console.WriteLine($"SetPoint: {setPoint} {unit}"); // 输出 "SetPoint: 25 ℃"
(3)配置集合操作

提供丰富的集合级操作方法,满足批量管理需求:

  • Keys(string superKey = ""):获取所有配置的键(含层级路径,如 Device1.Temperature.SetPoint)。
  • GetSettingDictionary():将所有嵌套配置扁平化为 “键路径 -Setting” 的字典,便于批量遍历。
  • GetDictionary():将所有数值型配置扁平化为 “键路径 -double[]” 的字典。
  • updateSettings(Dictionary<string, double[]> dict):批量更新数值型配置。
(4)配置对比(实用功能)

compare(SettingContainer other, bool swap = true, double tolerance = 0.0) 方法:

  • 对比当前容器与另一个容器的配置差异,返回差异字典(键路径 - 差异描述)。
  • 支持数值容忍度(tolerance),避免浮点精度问题导致的误判。
  • 支持忽略时间戳(SettingTimeStamp)和版本号(AcuShape.PROCESSING.version)等动态字段。
(5)JSON 序列化与反序列化

重写 ToString(string level) 方法,将嵌套容器结构转换为层级化 JSON(含 SettingsContainers 和 Settings 节点),反序列化时通过 FromString2 方法递归解析嵌套结构。

四、核心设计亮点

1. 类型安全与灵活性平衡

  • 通过隐式类型转换简化代码(如 double 直接转为 Setting),同时通过抽象类和接口约束确保类型安全。
  • 支持 double/string/ 多维数组等多种数据类型,覆盖绝大多数配置场景。

2. 层级化配置管理

  • SettingContainer 的 “点分隔符” 索引器,解决嵌套配置的访问痛点,比传统字典嵌套更直观。

3. 序列化与可移植性

  • 同时支持 JSON 字符串转换(便于日志和人工编辑)和 .NET 序列化(便于跨进程传输),满足不同场景的可移植需求。

4. 元数据管理

  • otherInfo 字典存储时间戳、版本、单位等元数据,让配置不仅包含 “数据”,还包含 “数据的描述信息”,便于追溯和维护。

五、典型应用场景

  1. 工业设备参数配置:存储 PLC、传感器的参数(如温度阈值、电机转速),通过 Setting 存储单设备参数,SettingContainer 管理多设备集合。
  2. 系统设置管理:存储软件的层级化设置(如 System.Network.IPSystem.Serial.BaudRate),通过 SettingContainer 实现路径化访问。
  3. 配置备份与恢复:通过 ToString() 将配置转为 JSON 字符串备份,恢复时通过 FromString() 解析,支持人工编辑备份文件。
  4. 配置对比与同步:通过 SettingContainer.compare() 方法对比本地与远程设备的配置差异,实现增量同步。

六、使用注意事项

  1. 隐式转换的异常风险:隐式转换时会检查 Setting 实例和数据长度(如 GenericSetting → double 要求 Values 非空且长度≥1),需确保数据合法性,避免抛出 Exception
  2. JSON 格式兼容性FromString() 方法依赖固定的 JSON 结构(含 OtherInfoValuesStrings 节点),自定义 JSON 时需遵循格式要求。
  3. 嵌套深度限制SettingContainer 的嵌套深度无硬限制,但过深的嵌套会影响性能和可读性,建议控制在 3-5 层以内。
  4. 线程安全:当前实现未包含线程安全控制,多线程并发访问时需手动添加锁(如 lock),避免字典操作冲突。

七、总结

该配置数据管理体系通过 “接口 - 抽象类 - 具体类 - 容器类” 的层级设计,实现了 “单一配置项→复杂嵌套配置” 的全场景覆盖,兼具类型安全、灵活性、可移植性三大优势。无论是工业设备参数管理,还是软件系统设置,都能通过该体系实现标准化、可维护的配置管理,是一套设计精良的配置解决方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/97586.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/97586.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PitVis-2023挑战赛:内镜下垂体瘤手术视频中的手术流程识别|文献速递-深度学习人工智能医疗图像

Title题目PitVis-2023 challenge: Workflow recognition in videos of endoscopic pituitary surgeryPitVis-2023挑战赛&#xff1a;内镜下垂体瘤手术视频中的手术流程识别01文献速递介绍内镜视觉挑战赛与PitVis-2023挑战赛背景及核心内容 “内镜视觉&#xff08;EndoVis&#…

2025年8月个人工作生活总结

本文为 2025年8月工作生活总结。研发编码 无处不在的AI 现在很多地方都在推AI&#xff0c;广西的人工智能走在前列&#xff0c;要赋能各行各业。至于我&#xff0c;主要就是在写点代码&#xff0c;写点交差的文档。其实现在我已经有点分析哪些代码哪些文字是AI写的了。我工作用…

Dubbo常见面试题

1、默认使用的是什么通信框架&#xff0c;还有别的选择吗? 默认也推荐使用netty框架&#xff0c;还有mina。 2、服务调用是阻塞的吗&#xff1f; 默认是阻塞的&#xff0c;可以异步调用&#xff0c;没有返回值的可以这么做。 3、一般使用什么注册中心&#xff1f;还有别的…

简单的加密算法

// 加密函数&#xff08;32位版本&#xff09; //这里的 data 是ID&#xff0c; dword encrypt(dword data, dword key, int shift) {data ^ key; // 第一步&#xff1a;异或混淆// 循环左移&#xff08;shift范围1-31&#xff09;return (data << sh…

升级的MS9125S USB投屏控制芯片(VGAHD输出)

MS9125S是一款USB单芯片投屏器&#xff0c;内部集成了USB 2.0控制器和数据收发模块、视频DAC、HD接口和音视频处理模块&#xff0c;支持压缩视频传输。MS9125S可以通过USB接口显示或者扩展PC、智能手机、平板电脑的显示信息到更大尺寸的显示设备上&#xff0c;支持VGA和HD视频接…

求欧拉回路:Hierholzer算法图解模拟

代码模板&#xff1a;List<Integer> resultList new ArrayList<>();List<Integer> hierholzer() {dfs(0);resultList.add(0);// 数组反转Collections.reverse(resultList);return resultList; }void dfs(int start) {for(int end : G[start]) {if(!vis[star…

Kafka面试精讲 Day 2:Topic、Partition与Replica机制

【Kafka面试精讲 Day 2】Topic、Partition与Replica机制 在“Kafka面试精讲”系列的第二天&#xff0c;我们将深入剖析Kafka最核心的三大数据组织机制&#xff1a;Topic&#xff08;主题&#xff09;、Partition&#xff08;分区&#xff09;与Replica&#xff08;副本&#x…

【备战2025数模国赛】(三)数模常见赛题类型及解决办法

在进行数学建模竞赛时&#xff0c;很多同学面临的第一个挑战是如何对赛题进行归类&#xff0c;并选择合适的模型。本篇梳理了数学建模中最常见的几类赛题&#xff0c;并针对每类题型提供了基本的解决思路&#xff0c;帮助大家快速选择合适的解题方法&#xff0c;高效完成模型构…

LabVIEW测斜设备承压试验台

为保障煤矿井下地质勘探钻孔中测斜装备的可靠运行&#xff0c;设计基于 LabVIEW的钻孔测斜设备承压性能试验台。该试验台以气动增压泵为压力执行元件&#xff0c;结合虚拟仪器与 PLC 控制技术&#xff0c;可精准模拟井下压力环境&#xff0c;完成水压、疲劳等试验&#xff0c;实…

四、练习1:Git基础操作

练习1&#xff1a;Git基础操作 练习目标 通过实际操作掌握Git的基本命令&#xff0c;包括初始化仓库、添加文件、提交更改等。 练习步骤 步骤1&#xff1a;环境准备 确保已安装Git配置用户信息&#xff08;如果未配置&#xff09; # 检查Git版本 git --version# 配置用户信息 g…

RK3399内核驱动实战:获取设备号控制LED的四种方法(由浅入深、代码注释详尽)

RK3399 内核驱动实战&#xff1a;获取设备号控制 LED 的四种方法&#xff08;由浅入深、代码注释详尽&#xff09; 在 Linux 字符设备驱动开发中&#xff0c;设备号&#xff08;major minor&#xff09;是内核与用户空间沟通的桥梁。文章围绕设备号这一条线展开&#xff0c;从…

2025年AI智能体开源技术栈全面解析:从基础框架到垂直应用

2025年&#xff0c;开源AI智能体技术正以前所未有的速度重塑人工智能领域&#xff0c;从单一任务处理到复杂多智能体协作&#xff0c;开源生态已成为技术创新的核心驱动力。一、开源AI智能体生态概述 1.1 技术演进与发展历程 AI智能体技术经历了从规则式智能体&#xff08;2015…

Empire: LupinOne靶场渗透

Empire: LupinOne 来自 <https://www.vulnhub.com/entry/empire-lupinone,750/#top> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.128&#xff0c;靶场IP192.16…

飞腾2000+/64核 PCIE扫描异常问题排查

1、背景介绍近期项目中采用全国产飞腾计算模块搭配一块FPGA模块&#xff08;FPGA为复旦微的VU9P&#xff09;&#xff0c;实现业务数据的收发。FPGA中采用了Xilinx的XDMA IP核&#xff0c;飞腾计算模块中的FT2000/64核处理器通过PEU1的一路 PCIE3.0x8与VU9P相连接&#xff0c;发…

证明与激励:Walrus 可编程数据如何通过激励可用性证明获得安全性

Walrus 的可用性证明&#xff08;Proof of Availability&#xff0c;PoA&#xff09; 是部署在 Sui 上的链上凭证&#xff0c;它为数据托管创建了一个可验证的公开记录&#xff0c;并作为存储服务正式启动的标志。PoA 中的“激励”来自一个健全的经济框架&#xff1a;存储节点需…

云存储(参考自腾讯云计算工程师认证)

目录 存储基础知识&#xff1a; RAID&#xff1a; 云存储概述&#xff1a; 云存储产品&#xff1a; CBS&#xff1a; CFS文件存储&#xff1a; COS对象存储&#xff1a; 云存储安全&#xff1a; 存储基础知识&#xff1a; 机械硬盘&#xff1a;HDD&#xff0c;即传统硬…

面试tips--JVM(2)--对象创建的过程

一、创建对象的完整过程1. 类加载检查JVM 遇到 new 指令时&#xff0c;首先去检查这个类 User 是否已经被加载、解析和初始化过。如果没有&#xff0c;就先执行 类加载过程&#xff08;加载 .class 文件到方法区/元空间、创建 Class 对象等&#xff09;。【这个过程就是加载、验…

【Web安全】CRLF注入攻击深度解析:原理、场景与安全测试防御指南

文章目录前言&#xff1a;为什么CRLF注入是安全测试不可忽视的威胁&#xff1f;1. CRLF注入核心原理&#xff1a;从字符定义到协议依赖1.1 什么是CRLF&#xff1f;1.2 CRLF在HTTP协议中的关键作用1.3 CRLF注入的本质&#xff1a;格式混淆攻击2. CRLF注入典型利用场景与安全测试…

【安全学习】DVWA 靶场 SQL 注入漏洞原理分析与防御策略(教育用途)

注意&#xff1a;本文内容仅用于合法授权的安全研究、教学演示及漏洞复现&#xff0c;严禁用于任何未授权的系统或网络环境。 所有操作需在本地沙箱或个人可控靶场中执行&#xff0c;切勿对生产环境、他人系统进行测试&#xff0c;非法使用后果自负。&#x1f4cc; 法律与道德双…

Langflow Memory 技术深度分析

Langflow Memory 技术深度分析 1. Memory 技术概述和设计理念 1.1 技术概述 Langflow 的 Memory 系统是一个多层次的记忆管理框架&#xff0c;专门设计用于处理对话历史、上下文状态和会话数据的存储与检索。该系统采用了分层架构设计&#xff0c;支持多种记忆类型和存储后端&a…