如何简化TryGetValue以直接获取字典值对象的属性?
当然可以!我们可以通过扩展方法+Lambda表达式的组合来封装这个逻辑,既能简化重复的TryGetValue代码,又能优雅地直接提取值对象的指定属性,还能轻松处理类型转换的场景。
解决方案:封装扩展方法简化属性提取
我们可以针对Dictionary<TKey, TValue>写几个通用的扩展方法,把TryGetValue的判断逻辑封装进去,同时通过Lambda直接指定要提取的属性。
基础版:直接提取属性值
这个版本适用于你明确知道属性类型的场景,编译时就能保证类型安全:
public static class DictionaryExtensions { // 核心方法:获取指定key对应值对象的属性,返回属性类型 public static TResult GetProperty<TKey, TValue, TResult>( this Dictionary<TKey, TValue> dict, TKey key, Func<TValue, TResult> propertySelector) { return dict.TryGetValue(key, out var value) ? propertySelector(value) : default(TResult); } // 带自定义默认值的重载,更灵活 public static TResult GetProperty<TKey, TValue, TResult>( this Dictionary<TKey, TValue> dict, TKey key, Func<TValue, TResult> propertySelector, TResult defaultValue) { return dict.TryGetValue(key, out var value) ? propertySelector(value) : defaultValue; } }
使用示例
假设我们有这样的实体类:
public class Foo { public int A { get; set; } public string B { get; set; } }
使用扩展方法的代码会非常简洁:
var fooDict = new Dictionary<string, Foo> { { "first", new Foo { A = 100, B = "Hello" } }, { "second", new Foo { A = 200, B = "World" } } }; // 直接提取first的A属性(int类型) int firstA = fooDict.GetProperty("first", foo => foo.A); // 输出:100 // 提取不存在的key的属性,返回int默认值0 int missingA = fooDict.GetProperty("missingKey", foo => foo.A); // 输出:0 // 自定义默认值的情况 string missingB = fooDict.GetProperty("missingKey", foo => foo.B, "DefaultText"); // 输出:DefaultText
进阶版:处理类型转换场景
如果你的值对象属性是object类型,需要转换成指定类型(比如把object转int),可以再写一个专门处理类型转换的重载:
public static class DictionaryExtensions { // 处理属性值需要类型转换的情况 public static TResult GetConvertedProperty<TKey, TValue>( this Dictionary<TKey, TValue> dict, TKey key, Func<TValue, object> propertySelector, TResult defaultValue) { if (!dict.TryGetValue(key, out var value)) return defaultValue; var propertyValue = propertySelector(value); // 先尝试直接类型转换 if (propertyValue is TResult result) return result; // 尝试通用类型转换(处理字符串转数字等场景) try { return (TResult)Convert.ChangeType(propertyValue, typeof(TResult)); } catch (Exception) { // 转换失败返回默认值 return defaultValue; } } }
使用示例
假设Foo有一个object类型的属性:
public class Foo { public object C { get; set; } }
使用这个方法处理类型转换:
var fooDict = new Dictionary<string, Foo> { { "numStr", new Foo { C = "123" } }, { "numInt", new Foo { C = 456 } }, { "invalid", new Foo { C = "NotANumber" } } }; // 把字符串"123"转成int int strToInt = fooDict.GetConvertedProperty("numStr", foo => foo.C, 0); // 输出:123 // 直接提取int类型的属性 int intValue = fooDict.GetConvertedProperty("numInt", foo => foo.C, 0); // 输出:456 // 转换失败的情况,返回默认值0 int invalidConvert = fooDict.GetConvertedProperty("invalid", foo => foo.C, 0); // 输出:0
为什么这么做?
- 减少重复代码:不用每次都写
if (dict.TryGetValue(...))的判断逻辑 - 代码更可读:通过Lambda直接指定要提取的属性,一目了然
- 类型安全:编译时就能检查属性是否存在、类型是否匹配
- 灵活性高:通过重载可以处理默认值、类型转换等多种场景
内容的提问来源于stack exchange,提问作者Cerzi
相关产品推荐
相关产品推荐

