184 lines
5.1 KiB
C#
184 lines
5.1 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
namespace Learn.Utils;
|
|
|
|
public class ConfigItemAttribute(string name) : Attribute
|
|
{
|
|
public readonly string Name = name;
|
|
}
|
|
|
|
public interface IConfigItem
|
|
{
|
|
public void OnBeforeSave()
|
|
{
|
|
}
|
|
|
|
public void OnAfterLoad()
|
|
{
|
|
}
|
|
}
|
|
|
|
public sealed class Configs
|
|
{
|
|
private static readonly ConcurrentDictionary<Type, string> Cache = new();
|
|
private readonly ConcurrentDictionary<string, IConfigItem> _configObjects = new();
|
|
private readonly ConcurrentDictionary<string, JObject> _configs = new();
|
|
|
|
public string ConfigPath { get; set; } = string.Empty;
|
|
|
|
private static string GetConfigItemName(Type type)
|
|
{
|
|
if (Cache.TryGetValue(type, out var name)) return name;
|
|
name = type.Name;
|
|
if(type.GetCustomAttribute(typeof(ConfigItemAttribute)) is ConfigItemAttribute info)
|
|
{
|
|
name = string.IsNullOrEmpty(info.Name) ? type.Name : info.Name;
|
|
}
|
|
Cache[type] = name;
|
|
return name;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取配置项对象
|
|
/// </summary>
|
|
/// <typeparam name="T">配置项类</typeparam>
|
|
/// <remarks>获取的配置项对象是单例的</remarks>
|
|
/// <returns>配置项对象</returns>
|
|
public T Get<T>() where T : class, IConfigItem, new()
|
|
{
|
|
var name = GetConfigItemName(typeof(T));
|
|
if (_configObjects.TryGetValue(name, out var value))
|
|
{
|
|
return (T) value;
|
|
}
|
|
T result;
|
|
if (_configs.TryGetValue(name, out var jObject))
|
|
{
|
|
result = jObject.ToObject<T>();
|
|
result.OnAfterLoad();
|
|
}
|
|
else
|
|
{
|
|
result = new T();
|
|
}
|
|
_configObjects[name] = result;
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 重置某个配置项。重置完后再取就是一个新的配置项
|
|
/// </summary>
|
|
/// <typeparam name="T">配置项类</typeparam>
|
|
public void Reset<T>() where T : class, IConfigItem, new()
|
|
{
|
|
var name = GetConfigItemName(typeof(T));
|
|
_configs.TryRemove(name, out _);
|
|
_configObjects.Remove(name, out _);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 清空当前配置并重新从文件中加载配置
|
|
/// </summary>
|
|
/// <param name="createDefaultIfNotExist">当不存在配置文件路径创建默认配置</param>
|
|
/// <returns>加载是否成功。无论是否加载成功,当前配置都会被清空</returns>
|
|
public bool Load(bool createDefaultIfNotExist)
|
|
{
|
|
_configs.Clear();
|
|
_configObjects.Clear();
|
|
if (string.IsNullOrEmpty(ConfigPath))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!File.Exists(ConfigPath))
|
|
{
|
|
if (!createDefaultIfNotExist) return false;
|
|
if (!CreateEmptyConfig(ConfigPath)) return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
var configJson = File.ReadAllText(ConfigPath);
|
|
var config = JObject.Parse(configJson);
|
|
foreach (var kv in config)
|
|
{
|
|
_configs[kv.Key] = kv.Value.ToObject<JObject>();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 将当前配置保存到文件中
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool Save()
|
|
{
|
|
if (string.IsNullOrEmpty(ConfigPath)) return false;
|
|
try
|
|
{
|
|
foreach (var config in _configObjects)
|
|
{
|
|
config.Value.OnBeforeSave();
|
|
_configs[config.Key] = JObject.FromObject(config.Value);
|
|
}
|
|
|
|
File.WriteAllText(ConfigPath, JsonConvert.SerializeObject(_configs, Formatting.Indented));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static bool CreateEmptyConfig(string filePath)
|
|
{
|
|
var configItemTypes = AppDomain.CurrentDomain.GetAssemblies()
|
|
.SelectMany(assembly =>
|
|
{
|
|
try
|
|
{
|
|
return assembly.GetTypes();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return Array.Empty<Type>();
|
|
}
|
|
})
|
|
.Where(type => type.IsClass &&
|
|
!type.IsAbstract &&
|
|
typeof(IConfigItem).IsAssignableFrom(type))
|
|
.ToList();
|
|
|
|
var configs = new Dictionary<string, IConfigItem>();
|
|
foreach (var type in configItemTypes)
|
|
{
|
|
var name = GetConfigItemName(type);
|
|
var item = (IConfigItem) Activator.CreateInstance(type);
|
|
item.OnBeforeSave();
|
|
configs[name] = item;
|
|
|
|
}
|
|
try
|
|
{
|
|
File.WriteAllText(filePath, JsonConvert.SerializeObject(configs, Formatting.Indented));
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
} |