文章目錄
- 深入分析 ConfigManager<TKey, TValue> 類
- 1. 類設計概述
- 2. 核心成員分析
- 2.1 字段和屬性
- 2.2 構造函數
- 3. 數據加載機制
- 4. CRUD 操作方法
- 4.1 添加數據
- 4.2 刪除數據
- 4.3 更新數據
- 4.4 查詢數據
- 4.5 清空數據
- 5. 數據持久化
- 6. 設計亮點
- 7. 使用示例
ConfigManager<TKey, TValue> 是一個泛型抽象類,用于管理鍵值對配置數據的加載、存儲和操作。下面將從多個維度全面分析這個類的設計和實現。
public abstract class ConfigManager<TKey, TValue>
{private readonly ConcurrentDictionary<TKey, TValue> _datas;protected abstract string ModulePath { get; }private readonly string _path;public IReadOnlyDictionary<TKey, TValue> Datas => _datas;protected ConfigManager(){_path = $"{path1}/{path2}{ModulePath}";_datas = LoadData() ?? new ConcurrentDictionary<TKey, TValue>();}private ConcurrentDictionary<TKey, TValue> LoadData(){try{var loadedData = JsonHelper_S.GetData<Dictionary<TKey, TValue>>(_path);return loadedData != null? new ConcurrentDictionary<TKey, TValue>(loadedData): new ConcurrentDictionary<TKey, TValue>();}catch (Exception ex){Console.WriteLine($"Error loading config data: {ex.Message}");return new ConcurrentDictionary<TKey, TValue>();}}public void Add(TKey key, TValue value){if (_datas.TryAdd(key, value)){//Task.Run(() => JsonHelper_S.SaveData(_datas.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), _path));}}public bool Remove(TKey key){bool removed = _datas.TryRemove(key, out _);if (removed){//Task.Run(() => JsonHelper_S.SaveData(_datas.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), _path));}return removed;}public bool TryGetValue(TKey key, out TValue value){return _datas.TryGetValue(key, out value);}public void Update(TKey key, TValue value){_datas.AddOrUpdate(key, value, (k, oldValue) => value);//Task.Run(() => JsonHelper_S.SaveData(_datas.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), _path));}public void Clear(){_datas.Clear();//Task.Run(() => JsonHelper_S.SaveData(_datas.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), _path));}public void Save(){Task.Run(() => JsonHelper_S.SaveData(_datas.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), _path));}
}
深入分析 ConfigManager<TKey, TValue> 類
ConfigManager<TKey, TValue>
是一個泛型抽象類,用于管理鍵值對配置數據的加載、存儲和操作。下面我將從多個維度全面分析這個類的設計和實現。
1. 類設計概述
這是一個抽象基類,使用泛型參數 TKey
和 TValue
來支持不同類型的鍵值對配置。主要特點包括:
- 使用
ConcurrentDictionary
保證線程安全 - 抽象路徑定義,由子類實現具體配置路徑
- 提供基本的 CRUD 操作
- 自動持久化到 JSON 文件
- 錯誤處理和日志記錄
2. 核心成員分析
2.1 字段和屬性
private readonly ConcurrentDictionary<TKey, TValue> _datas;
protected abstract string ModulePath { get; }
private readonly string _path;
public IReadOnlyDictionary<TKey, TValue> Datas => _datas;
_datas
: 使用ConcurrentDictionary
存儲配置數據,確保線程安全ModulePath
: 抽象屬性,子類必須實現,定義配置文件的相對路徑_path
: 完整的配置文件路徑,由構造函數初始化Datas
: 只讀屬性,提供對配置數據的只讀訪問
2.2 構造函數
protected ConfigManager()
{_path = $"{path1}/{path2}{ModulePath}";_datas = LoadData() ?? new ConcurrentDictionary<TKey, TValue>();
}
- 構造完整路徑:組合基礎路徑和模塊路徑
- 初始化數據:調用
LoadData()
方法加載現有配置,失敗則創建空字典
3. 數據加載機制
private ConcurrentDictionary<TKey, TValue> LoadData()
{try{var loadedData = JsonHelper_S.GetData<Dictionary<TKey, TValue>>(_path);return loadedData != null? new ConcurrentDictionary<TKey, TValue>(loadedData): new ConcurrentDictionary<TKey, TValue>();}catch (Exception ex){Console.WriteLine($"Error loading config data: {ex.Message}");return new ConcurrentDictionary<TKey, TValue>();}
}
- 使用
JsonHelper_S.GetData
從 JSON 文件加載數據 - 錯誤處理:捕獲異常并記錄錯誤日志
- 回退機制:加載失敗時返回空字典
4. CRUD 操作方法
4.1 添加數據
public void Add(TKey key, TValue value)
{if (_datas.TryAdd(key, value)){//Task.Run(() => JsonHelper_S.SaveData(_datas.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), _path));}
}
- 使用
TryAdd
確保線程安全 - 添加成功后注釋了異步保存邏輯(可能是為了性能考慮)
4.2 刪除數據
public bool Remove(TKey key)
{bool removed = _datas.TryRemove(key, out _);if (removed){//Task.Run(() => JsonHelper_S.SaveData(_datas.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), _path));}return removed;
}
- 使用
TryRemove
安全刪除 - 返回操作結果
- 刪除成功后注釋了異步保存
4.3 更新數據
public void Update(TKey key, TValue value)
{_datas.AddOrUpdate(key, value, (k, oldValue) => value);//Task.Run(() => JsonHelper_S.SaveData(_datas.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), _path));
}
- 使用
AddOrUpdate
原子操作 - 確保更新操作的線程安全性
- 注釋了異步保存
4.4 查詢數據
public bool TryGetValue(TKey key, out TValue value)
{return _datas.TryGetValue(key, out value);
}
- 標準字典查詢方法
- 使用
TryGetValue
模式避免異常
4.5 清空數據
public void Clear()
{_datas.Clear();//Task.Run(() => JsonHelper_S.SaveData(_datas.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), _path));
}
- 清空所有配置項
- 注釋了異步保存
5. 數據持久化
public void Save()
{Task.Run(() => JsonHelper_S.SaveData(_datas.ToDictionary(kvp => kvp.Key, kvp => kvp.Value), _path));
}
- 顯式保存方法
- 使用
Task.Run
異步執行保存操作 - 將
ConcurrentDictionary
轉換為普通Dictionary
后保存
6. 設計亮點
- 線程安全:全程使用
ConcurrentDictionary
確保多線程環境下的安全性 - 抽象設計:通過抽象
ModulePath
屬性支持不同模塊的配置管理 - 錯誤處理:加載數據時有完善的錯誤處理和回退機制
- 惰性持久化:注釋了自動保存,可能是為了避免頻繁IO操作
- 只讀接口:通過
IReadOnlyDictionary
暴露數據,防止外部修改
7. 使用示例
子類實現可能如下:
public class UserSettingsManager : ConfigManager<string, string>
{protected override string ModulePath => "/UserSettingsBase/UserSettingsConfigManagerIsLog";private static readonly Lazy<UserSettingsManager > _instance =new Lazy<UserSettingsManager >(() => new UserSettingsManager ());public static UserSettingsManager Instance => _instance.Value;private UserSettingsManager () : base() { }
}
使用示例:
var manager = new UserSettingsManager();
manager.Add("theme", "dark");
manager.Update("language", "en-US");
if(manager.TryGetValue("theme", out var theme))
{Console.WriteLine($"Current theme: {theme}");
}
manager.Save();