本文最后更新于 205 天前,其中的信息可能已经有所发展或是发生改变。
依赖
System.Text.Json
using System.IO;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
/// <summary>
/// 提供使用 JSON 快速加载和保存配置的功能。
/// </summary>
public abstract class JsonConfig
{
/// <summary>
/// 配置路径。
/// </summary>
[JsonIgnore]
public string Path { get; set; }
/// <summary>
/// 默认配置路径。
/// </summary>
protected virtual string DefaultPath => $"{GetType().Name}.json";
/// <summary>
/// 配置选项。
/// </summary>
[JsonIgnore]
public JsonConfigOptions Options { get; set; }
/// <summary>
/// 默认配置选项。
/// </summary>
protected virtual JsonConfigOptions DefaultOptions => null;
/// <summary>
/// 全局配置选项。
/// </summary>
public static JsonConfigOptions GlobalOptions { get; set; } = new();
/// <summary>
/// 加载配置。
/// </summary>
/// <typeparam name="T">配置类型。</typeparam>
/// <returns>配置实例。</returns>
public static T Load<T>() where T : JsonConfig, new()
{
return Load<T>(new T().DefaultPath, new T().DefaultOptions);
}
/// <summary>
/// 从指定路径加载配置。
/// </summary>
/// <typeparam name="T">配置类型。</typeparam>
/// <param name="path">配置路径。</param>
/// <returns>配置实例。</returns>
public static T Load<T>(string path) where T : JsonConfig, new()
{
return Load<T>(path, new T().DefaultOptions);
}
/// <summary>
/// 加载配置,使用指定选项。
/// </summary>
/// <typeparam name="T">配置类型。</typeparam>
/// <param name="options">配置选项。</param>
/// <returns>配置实例。</returns>
public static T Load<T>(JsonConfigOptions options) where T : JsonConfig, new()
{
return Load<T>(new T().DefaultPath, options);
}
/// <summary>
/// 从指定路径加载配置,使用指定选项。
/// </summary>
/// <typeparam name="T">配置类型。</typeparam>
/// <param name="path">配置路径。</param>
/// <param name="options">配置选项。</param>
/// <returns>配置实例。</returns>
public static T Load<T>(string path, JsonConfigOptions options) where T : JsonConfig, new()
{
var jco = options ?? GlobalOptions;
if (File.Exists(path))
{
string json = File.ReadAllText(path);
T config = JsonSerializer.Deserialize<T>(json, jco.SerializerOptions);
config.Path = path;
config.Options = options;
return config;
}
else if (jco.CreateNew)
{
T config = new();
config.Path = path;
config.Options = options;
if (jco.SaveNew)
config.Save();
return config;
}
else
{
return null;
}
}
/// <summary>
/// 尝试加载配置。
/// </summary>
/// <typeparam name="T">配置类型。</typeparam>
/// <param name="config">配置实例。</param>
/// <returns>是否成功。</returns>
public static bool TryLoad<T>(out T config) where T : JsonConfig, new()
{
return TryLoad(new T().DefaultPath, new T().DefaultOptions, out config);
}
/// <summary>
/// 尝试从指定路径加载配置。
/// </summary>
/// <typeparam name="T">配置类型。</typeparam>
/// <param name="path">配置路径。</param>
/// <param name="config">配置实例。</param>
/// <returns>是否成功。</returns>
public static bool TryLoad<T>(string path, out T config) where T : JsonConfig, new()
{
return TryLoad(path, new T().DefaultOptions, out config);
}
/// <summary>
/// 尝试加载配置,使用指定选项。
/// </summary>
/// <typeparam name="T">配置类型。</typeparam>
/// <param name="options">配置选项。</param>
/// <param name="config">配置实例。</param>
/// <returns>是否成功。</returns>
public static bool TryLoad<T>(JsonConfigOptions options, out T config) where T : JsonConfig, new()
{
return TryLoad(new T().DefaultPath, options, out config);
}
/// <summary>
/// 尝试从指定路径加载配置,使用指定选项。
/// </summary>
/// <typeparam name="T">配置类型。</typeparam>
/// <param name="path">配置路径。</param>
/// <param name="options">配置选项。</param>
/// <param name="config">配置实例。</param>
/// <returns>是否成功。</returns>
public static bool TryLoad<T>(string path, JsonConfigOptions options, out T config) where T : JsonConfig, new()
{
try
{
config = Load<T>(path, options);
return true;
}
catch
{
config = null;
return false;
}
}
/// <summary>
/// 保存配置。
/// </summary>
public void Save()
{
Save(Path, Options);
}
/// <summary>
/// 保存配置到指定路径。
/// </summary>
/// <param name="path">配置路径。</param>
public void Save(string path)
{
Save(path, Options);
}
/// <summary>
/// 保存配置,使用指定选项。
/// </summary>
/// <param name="options">配置选项。</param>
public void Save(JsonConfigOptions options)
{
Save(Path, options);
}
/// <summary>
/// 保存配置到指定路径,使用指定选项。
/// </summary>
/// <param name="path">配置路径。</param>
/// <param name="options">配置选项。</param>
public void Save(string path, JsonConfigOptions options)
{
var jco = options ?? GlobalOptions;
string json = JsonSerializer.Serialize(this, GetType(), jco.SerializerOptions);
File.WriteAllText(path, json);
}
/// <summary>
/// 尝试保存配置。
/// </summary>
/// <returns>是否成功。</returns>
public bool TrySave()
{
return TrySave(Path, Options);
}
/// <summary>
/// 尝试保存配置到指定路径。
/// </summary>
/// <param name="path">配置路径。</param>
/// <returns>是否成功。</returns>
public bool TrySave(string path)
{
return TrySave(path, Options);
}
/// <summary>
/// 尝试保存配置,使用指定选项。
/// </summary>
/// <param name="options">配置选项。</param>
/// <returns>是否成功。</returns>
public bool TrySave(JsonConfigOptions options)
{
return TrySave(Path, options);
}
/// <summary>
/// 尝试保存配置到指定路径,使用指定选项。
/// </summary>
/// <param name="path">配置路径。</param>
/// <param name="options">配置选项。</param>
/// <returns>是否成功。</returns>
public bool TrySave(string path, JsonConfigOptions options)
{
try
{
Save(path, options);
return true;
}
catch
{
return false;
}
}
}
/// <summary>
/// 提供与 <see cref="JsonConfig"/> 一起使用的选项。
/// </summary>
public sealed class JsonConfigOptions
{
/// <summary>
/// 初始化 <see cref="JsonConfigOptions"/> 类的新实例。
/// </summary>
public JsonConfigOptions() { }
/// <summary>
/// 将 <see cref="JsonConfigOptions"/> 实例的选项复制到新实例。
/// </summary>
/// <param name="options">要从中复制选项的选项实例。</param>
public JsonConfigOptions(JsonConfigOptions options)
{
CreateNew = options.CreateNew;
SaveNew = options.SaveNew;
SerializerOptions = options.SerializerOptions;
}
/// <summary>
/// 如果文件不存在,是否创建新配置。
/// </summary>
public bool CreateNew { get; set; } = true;
/// <summary>
/// 创建新配置后,是否立刻将其保存。
/// </summary>
public bool SaveNew { get; set; } = true;
/// <summary>
/// 用于序列化和反序列化的 <see cref="JsonSerializerOptions"/>。
/// </summary>
public JsonSerializerOptions SerializerOptions { get; set; } = new()
{
AllowTrailingCommas = true,
Converters = { new JsonStringEnumConverter() },
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals | JsonNumberHandling.AllowReadingFromString,
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
WriteIndented = true
};
}
快速上手
将 JsonConfig.cs
添加到项目中。
新建 Settings.cs
:
public class Settings : JsonConfig
{
public string MyString { get; set; }
}
这样快速加载和保存:
var settings = JsonConfig.Load<Settings>();
settings.MyString = "Hello!";
settings.Save();
更多示例
极简日志
public class Log : JsonConfig
{
protected override string DefaultPath => $"Logs\\{DateTime.Now:yyyyMMdd}.json";
protected override JsonConfigOptions DefaultOptions => new() { SaveNew = false };
public List<string> Messages { get; set; } = new();
}