解决ComboBox绑定Dictionary<string,T>设置选中项的类型转换异常
问题根因
KeyValuePair<TKey, TValue>是值类型(结构体),不支持泛型协变规则,因此无法直接将KeyValuePair<string, 任意具体T类型>的实例强转为KeyValuePair<string, object>,和T是引用类型还是值类型无关。
这段代码重构前可正常运行,是因为拆分程序集前的绑定逻辑隐式将字典元素装箱为非泛型枚举序列,重构后绑定源直接暴露了具体的泛型字典类型,运行时枚举阶段执行强转就触发了类型转换异常。
之前尝试的方案失效原因如下:
- 将遍历变量声明为
KeyValuePair<string, dynamic>时,本质还是要在枚举时把整个结构体强转为目标泛型类型,绕不过协变不支持的限制,运行时依然会抛出相同异常 as运算符仅支持引用类型或可空值类型的转换,KeyValuePair是普通值类型,用as做类型转换永远返回null- 直接声明
dynamic item遍历如果出现编译错误,一般是项目框架版本过低导致,换用下文的反射写法即可。
通用适配方案
两种写法都不需要关心字典Value的具体类型,可兼容所有Dictionary<string, T>类型的绑定源,包括你提到的Dictionary<string, NetworkFolder>、Dictionary<string, FileInfo>、Dictionary<string, int>等场景。
写法1:dynamic实现(代码最简)
遍历的时候不要指定KeyValuePair的泛型参数,直接将遍历变量声明为dynamic,运行时动态访问Key属性即可:
/// <summary> /// Attempt to set the combobox to the item with the supplied string /// </summary> protected void SetComboBoxSelection(ComboBox cmb, string ItemText) { if (cmb.DisplayMember.ToLower() == "key" && cmb.ValueMember.ToLower() == "value") { foreach (dynamic item in cmb.Items) { string key = item.Key; if (key == ItemText || key.HasPatternMatch(ItemText)) { cmb.SelectedItem = item; return; } } } }
注意:不要把遍历变量声明为KeyValuePair<string, dynamic>,否则还是会触发强转异常。
写法2:反射实现(兼容低版本框架/AOT编译场景)
如果项目不支持dynamic、或者开启了AOT编译不能用动态特性,可以通过反射取Key属性,ComboBox的列表数据量一般很小,反射的性能影响可以完全忽略:
/// <summary> /// Attempt to set the combobox to the item with the supplied string /// </summary> protected void SetComboBoxSelection(ComboBox cmb, string ItemText) { if (cmb.DisplayMember.ToLower() == "key" && cmb.ValueMember.ToLower() == "value") { foreach (object item in cmb.Items) { var keyProperty = item.GetType().GetProperty("Key"); if (keyProperty == null) continue; if (keyProperty.GetValue(item) is not string key) continue; if (key == ItemText || key.HasPatternMatch(ItemText)) { cmb.SelectedItem = item; return; } } } }
内容的提问来源于stack exchange,提问作者RFBomb
相关产品推荐
相关产品推荐

