C#如何为异构字典实现支持编译期检查的类型安全API
实现编译期类型安全的解决方案
推荐方案:强类型键绑定(零运行时开销,全编译期校验)
核心思路是放弃字符串作为键的入参,将键与对应类型的绑定关系提前到类型系统中,编译期即可完成所有校验,不需要dynamic也不需要运行时类型判断。
实现代码
首先定义强类型键类,预定义所有合法键与对应类型的映射:
public sealed class JsonKey<T> { public string KeyName { get; } private JsonKey(string keyName) => KeyName = keyName; // 预定义所有合法键,直接绑定类型 public static readonly JsonKey<int> FOO = new(nameof(FOO)); public static readonly JsonKey<string> BAR = new(nameof(BAR)); }
改写JsonDictionary实现:
public class JsonDictionary { private readonly IDictionary<string, object> _data = new Dictionary<string, object>(); public void Set<T>(JsonKey<T> key, T value) { _data[key.KeyName] = value; } public T Get<T>(JsonKey<T> key) { // 若担心内部逻辑出错可加运行时校验,正常业务场景编译期已保证类型匹配 return (T)_data[key.KeyName]; } }
调用示例
var dict = new JsonDictionary(); // 正常调用 dict.Set(JsonKey.FOO, 42); dict.Set(JsonKey.BAR, "value"); // 错误调用直接编译报错:无法将int类型的参数赋值给string类型的形参 // dict.Set(JsonKey.BAR, 56); // 自动推导返回值类型,不需要手动指定泛型参数 int foo = dict.Get(JsonKey.FOO); string bar = dict.Get(JsonKey.BAR);
备选方案:保留字符串键的实现
如果必须保留字符串作为入参,可先将Get方法改为泛型实现替换dynamic:
// 改写Get方法 public T Get<T>(string key) { if (typeof(T) != _keyTypes[key]) throw new InvalidOperationException($"类型不匹配:期望 {_keyTypes[key]},实际传入 {typeof(T)}"); return (T)_data[key]; }
调用方式:
int foo = dict.Get<int>("FOO"); string bar = dict.Get<string>("BAR");
如果需要支持字符串键的编译期类型校验,需要自行开发Roslyn代码分析器,识别该类的Set/Get方法调用,根据预定义的键类型映射检查参数类型是否匹配,不符合时触发编译告警。
内容的提问来源于stack exchange,提问作者malat
相关产品推荐
相关产品推荐

