C#基类泛型方法如何识别调用派生类类型 省略Load方法重复实现
两个需求都可以通过奇异递归模板模式(CRTP) 实现,将基类改造为泛型基类即可,不需要在每个派生类重复写Load方法、单例定义和重复逻辑。
完整改造代码
1. 泛型抽象基类
using Newtonsoft.Json; using Newtonsoft.Json.Serialization; // 泛型参数T为实际的派生配置类类型 public abstract class AbstractConfig<T> where T : AbstractConfig<T>, new() { [JsonIgnore] public string FileName { get; protected set; } public void Save() { File.WriteAllText(FileName, JsonConvert.SerializeObject(this, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new SubstituteNullWithEmptyStringContractResolver() })); } // 静态Load方法直接返回对应派生类类型,无需调用方指定泛型参数 public static T Load(string fileName) { T instance = JsonConvert.DeserializeObject<T>(File.ReadAllText(fileName), new JsonSerializerSettings { ContractResolver = new SubstituteNullWithEmptyStringContractResolver() }) ?? new T(); instance.FileName = fileName; // 自动赋值单例 Instance = instance; return instance; } // 全局单例,每个派生类独占一份 public static T Instance { get; set; } // 给主动new实例场景用的构造函数 protected AbstractConfig(string fileName) { FileName = fileName; } // 给Json反序列化用的无参构造 protected AbstractConfig() { } } // 你原有空字符串处理的ContractResolver,保持原来的实现即可 public class SubstituteNullWithEmptyStringContractResolver : DefaultContractResolver { // 原有逻辑不变 }
2. 派生配置类(无需重复写公共逻辑)
public class ConfigA : AbstractConfig<ConfigA> { [JsonProperty("test1")] public string Test1 { get; set; } [JsonProperty("test2")] public int Test2 { get; set; } public ConfigA(string fileName) : base(fileName) { } public ConfigA() { } } public class ConfigB : AbstractConfig<ConfigB> { [JsonProperty("test3")] public int Test3 { get; set; } [JsonProperty("test4")] public string Test4 { get; set; } public ConfigB(string fileName) : base(fileName) { } public ConfigB() { } }
使用示例(完全符合你要求的调用方式)
// 加载不需要写基类和泛型参数 ConfigA configA = ConfigA.Load("a.json"); ConfigB configB = ConfigB.Load("b.json"); // 单例直接调用,Load时已经自动赋值 var configASingleton = ConfigA.Instance; var configBSingleton = ConfigB.Instance; // 保存逻辑和原有用法完全兼容 ConfigA newConfigA = new ConfigA("a_new.json"); newConfigA.Test1 = "测试内容"; newConfigA.Save();
实现原理
C#中泛型类的静态成员是每个封闭构造类型独立存储的,也就是说AbstractConfig<ConfigA>的Load方法、Instance属性和AbstractConfig<ConfigB>的对应成员完全独立,刚好匹配每个派生配置类的专属静态成员需求,不需要重复实现。
内容的提问来源于stack exchange,提问作者whc2001
相关产品推荐
相关产品推荐

