using System.Collections.Concurrent; using System.Diagnostics; using System.Reflection; using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace BangumiRenamer.Utils; public class ConfigItemAttribute(string name) : Attribute { public readonly string Name = name; } public interface IConfigItem { public void BeforeSave() { } public void AfterLoad() { } } public interface IConfig { public T Get() where T : class, IConfigItem, new(); public void Reset() where T : class, IConfigItem, new(); public bool Save(); } public sealed class Config(string configPath) : IConfig { public static IConfig G => _G; public static Config _G { private get; set; } private static readonly ConcurrentDictionary Cache = new(); private readonly ConcurrentDictionary _configObjects = new(); private readonly ConcurrentDictionary _configs = new(); 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; } public T Get() 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(); result.AfterLoad(); } else { result = new T(); } _configObjects[name] = result; return result; } public void Reset() where T : class, IConfigItem, new() { var name = GetConfigItemName(typeof(T)); _configs.TryRemove(name, out _); _configObjects.Remove(name, out _); } public bool Load() { _configs.Clear(); _configObjects.Clear(); if (!File.Exists(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(); } } catch (Exception) { return false; } return true; } public bool Save() { if (string.IsNullOrEmpty(configPath)) return false; try { foreach (var config in _configObjects) { config.Value.BeforeSave(); _configs[config.Key] = JObject.FromObject(config.Value); } File.WriteAllText(configPath, JsonConvert.SerializeObject(_configs, Formatting.Indented)); } catch (Exception) { return false; } return true; } public static void CreateEmptyConfig() { var configItemTypes = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(assembly => { try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException) { return Array.Empty(); } }) .Where(type => type.IsClass && !type.IsAbstract && typeof(IConfigItem).IsAssignableFrom(type)) .ToList(); var filePath = "config.json"; var config = new Config(filePath); foreach (var type in configItemTypes) { var name = GetConfigItemName(type); config._configObjects[name] = (IConfigItem) Activator.CreateInstance(type); } config.Save(); if (File.Exists(filePath)) { // 使用 explorer.exe 的 /select 命令行参数 string argument = $"/select,\"{filePath}\""; // 启动 explorer.exe 进程 Process.Start("explorer.exe", argument); } } }