使用扩展方法为存储系统注册新类型时如何调用对应序列化扩展方法
解决方案
问题根因
扩展方法属于编译期静态绑定,你当前在JsonStorageManager中拿到的是IStorable类型的变量,编译器只会在IStorable的定义和对应扩展类中查找ToJson方法,自然找不到具体业务类的扩展实现。
另外你原有代码存在两处语法问题需要先修正:
- C#接口不能定义实例字段,
IStorable的StorageKey需要改为属性 IStorageManager的Save方法签名需要和实现类对齐,补充IStorable参数
修正后的基础接口定义:
public interface IStorageManager { void Save(IStorable obj); } public interface IStorable { // 改为只读属性,业务类中直接赋值即可 public string StorageKey { get; } }
方案一:动态绑定(最小改动)
如果可以接受运行时异常校验,只需要修改JsonStorageManager的Save方法,通过dynamic做运行时动态调度,自动匹配对应类型的ToJson扩展方法:
public class JsonStorageManager : IStorageManager { public void Save(IStorable obj) { try { // 转dynamic后运行时会自动查找对应类型的ToJson扩展方法 string json = ((dynamic)obj).ToJson(); JsonSerializer.SaveToFile(obj.StorageKey, json); } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { throw new NotSupportedException($"类型 {obj.GetType().Name} 未实现ToJson扩展方法,无法完成JSON存储"); } } }
注意需要将所有业务类的ToJson扩展类统一放到同一个命名空间下,JsonStorageManager所在文件引用该命名空间即可。
方案二:序列化注册器(类型安全,推荐)
如果需要编译期层面的安全校验,避免运行时异常,可以通过策略模式实现序列化方法的自动注册,完全满足你的解耦要求:
- 实现序列化注册器,维护类型和序列化方法的映射关系
public static class JsonSerializerRegistry { private static readonly Dictionary<Type, Func<IStorable, string>> _serializerMap = new(); // 注册指定类型的序列化方法 public static void Register<T>(Func<T, string> serializer) where T : IStorable { _serializerMap[typeof(T)] = obj => serializer((T)obj); } // 执行序列化 public static string Serialize(IStorable obj) { if (_serializerMap.TryGetValue(obj.GetType(), out var serializer)) { return serializer(obj); } throw new NotSupportedException($"类型 {obj.GetType().Name} 未注册JSON序列化方法"); } }
- 在扩展类的静态构造函数中注册序列化方法,新增业务类时只需要在对应扩展文件中添加注册逻辑即可:
static class MyDataSetExtension { // 静态构造函数在类第一次被访问时执行,自动完成注册 static MyDataSetExtension() { JsonSerializerRegistry.Register<MyDataSet>(ToJson); } public static string ToJson(this MyDataSet set) { // 你的自定义序列化逻辑 return JsonSerializer.Serialize(set); } }
- 调整
JsonStorageManager的Save方法:
public void Save(IStorable obj) { string json = JsonSerializerRegistry.Serialize(obj); JsonSerializer.SaveToFile(obj.StorageKey, json); }
后续迁移适配说明
后续需要切换到云SQL存储时,只需要实现SqlStorageManager,按照同样的规则做SQL读写逻辑的扩展注册即可,不需要修改任何业务类的原有代码,完全符合开闭原则。
内容的提问来源于stack exchange,提问作者javirs
相关产品推荐
相关产品推荐

