如何在不使用第三方库时消除LINQ查询中的重复代码?
可以通过反射实现单一方法(基于字符串属性名)
当然可以,你可以利用.NET自带的反射功能,通过传入字符串形式的属性名,将这些重复方法合并成一个通用方法,全程不需要任何第三方库,完全依赖.NET基础类库实现。
实现代码示例
private IEnumerable<decimal?> GetNonNullPropertyValues(IEnumerable<Rectangle> rectangles, string propertyName) { // 获取Rectangle类型中指定名称的属性 PropertyInfo property = typeof(Rectangle).GetProperty(propertyName); if (property == null) { throw new ArgumentException($"属性 {propertyName} 在Rectangle类型中不存在"); } return rectangles .Where(rect => { // 反射获取属性值并判空 object value = property.GetValue(rect); return value != null; }) .Select(rect => (decimal?)property.GetValue(rect)); }
使用方式
调用时直接传入对应的属性名字符串即可,推荐用nameof()代替硬编码字符串,避免拼写错误且支持重命名时的编译检查:
var widths = GetNonNullPropertyValues(rectangles, nameof(Rectangle.Width)); var heights = GetNonNullPropertyValues(rectangles, nameof(Rectangle.Height)); var diameters = GetNonNullPropertyValues(rectangles, nameof(Rectangle.Diameter)); var weights = GetNonNullPropertyValues(rectangles, nameof(Rectangle.Weight));
性能优化建议
反射存在一定的运行时开销,如果你的代码处于性能敏感场景,可以预先缓存PropertyInfo,避免每次调用重复获取:
private static readonly Dictionary<string, PropertyInfo> _rectangleProperties = new(); private IEnumerable<decimal?> GetNonNullPropertyValues(IEnumerable<Rectangle> rectangles, string propertyName) { if (!_rectangleProperties.TryGetValue(propertyName, out PropertyInfo property)) { property = typeof(Rectangle).GetProperty(propertyName); if (property == null) { throw new ArgumentException($"属性 {propertyName} 在Rectangle类型中不存在"); } _rectangleProperties.Add(propertyName, property); } // 后续判空、取值逻辑同上 }
更高效的替代方案(无需字符串)
如果不需要严格通过字符串指定属性,还可以用Func<Rectangle, decimal?>作为参数,这种方式是编译时绑定,性能比反射好很多,同时保留类型安全:
private IEnumerable<decimal?> GetNonNullPropertyValues(IEnumerable<Rectangle> rectangles, Func<Rectangle, decimal?> propertySelector) { return rectangles .Where(rect => propertySelector(rect) != null) .Select(propertySelector); }
调用方式更简洁:
var widths = GetNonNullPropertyValues(rectangles, r => r.Width);
内容的提问来源于stack exchange,提问作者Learner
相关产品推荐
相关产品推荐

