递归处理对象字符串属性时Lambda表达式参数类型不匹配问题
解决递归处理对象String属性时的Expression Lambda类型不匹配问题
嘿,我来帮你搞定这个头疼的类型错误!咱们先把问题根源理清楚,再给你一个靠谱的修正方案。
问题到底出在哪?
你遇到的报错核心是递归调用时泛型参数被错误推断了:
- 当处理
A里的BInfo属性(类型是B)时,你调用Translate(temp),这里temp的编译时类型是object,所以泛型参数T会被自动推断成object。 - 但你创建的
ParameterExpression是基于B的实际类型(t = need.GetType()拿到的是B),这时候要构建Expression<Func<object, string>>,参数表达式却是B类型,类型完全不匹配,自然就炸了。
另外,你的代码还有两个小漏洞:数组处理的分支是空的,而且像List<C>这类泛型集合,当前的IsClass判断会进入,但没法遍历里面的元素处理。
修正后的完整代码
我调整了几个关键地方,不仅解决了类型错误,还完善了集合和数组的处理逻辑:
public T Translate<T>(T need) where T : class { if (need == null) return default(T); var objType = need.GetType(); var properties = objType.GetProperties(); foreach (var prop in properties) { var propValue = prop.GetValue(need); // 处理字符串属性:直接用反射读写,不用绕Expression了 if (prop.PropertyType == typeof(string)) { if (propValue != null) { var translated = DoTranslation(need, prop.Name, ((ILo)need).GetId()); prop.SetValue(need, translated); } continue; } // 处理泛型集合(比如List<C>) if (prop.PropertyType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(prop.PropertyType)) { if (propValue == null) continue; var elementType = prop.PropertyType.GetGenericArguments()[0]; // 只处理实现ILo的引用类型元素 if (!elementType.IsClass || !typeof(ILo).IsAssignableFrom(elementType)) continue; // 遍历每个元素,反射调用泛型Translate方法 foreach (var item in (IEnumerable)propValue) { var translateMethod = typeof(YourClass).GetMethod(nameof(Translate)).MakeGenericMethod(elementType); translateMethod.Invoke(this, new[] { item }); } continue; } // 处理数组 if (prop.PropertyType.IsArray) { if (propValue == null) continue; var elementType = prop.PropertyType.GetElementType(); if (!elementType.IsClass || !typeof(ILo).IsAssignableFrom(elementType)) continue; var array = (Array)propValue; for (int i = 0; i < array.Length; i++) { var item = array.GetValue(i); var translateMethod = typeof(YourClass).GetMethod(nameof(Translate)).MakeGenericMethod(elementType); var processedItem = translateMethod.Invoke(this, new[] { item }); array.SetValue(processedItem, i); } continue; } // 处理单个引用类型对象(比如BInfo) if (prop.PropertyType.IsClass && typeof(ILo).IsAssignableFrom(prop.PropertyType)) { if (propValue == null) continue; // 明确指定泛型类型,避免被推断成object var translateMethod = typeof(YourClass).GetMethod(nameof(Translate)).MakeGenericMethod(prop.PropertyType); translateMethod.Invoke(this, new[] { propValue }); } } return need; } // 对应调整DoTranslation方法,用属性名来获取原值 private string DoTranslation(object targetObj, string propName, Guid id) { var originalValue = targetObj.GetType().GetProperty(propName).GetValue(targetObj) as string; // 这里替换成你的实际翻译逻辑 return $"Translated_{originalValue}_{id}"; }
核心改进说明
- 搞定泛型推断问题:递归调用时不再直接用
Translate(temp),而是通过反射获取泛型方法并指定具体类型,彻底避免T被推断成object - 简化字符串处理:直接用反射读写属性值,去掉了容易出问题的Expression Lambda,代码更简洁还解决了类型错误
- 补全集合/数组逻辑:新增了泛型集合和数组的遍历处理,确保嵌套集合里的字符串属性也能被翻译
- 增加类型安全检查:只处理实现
ILo的引用类型,避免对值类型(比如Guid)做无用处理
为啥原来的Expression会报错?
再给你掰扯清楚:当处理B对象时,T被推断成object,你要构建的是Expression<Func<object, string>>,但ParameterExpression的类型是B,委托的参数类型是object,两者不兼容,CLR自然就抛出那个类型不匹配的错误了。如果非要用Expression,得把参数表达式转成object类型,但完全没必要,反射直接处理更简单。
内容的提问来源于stack exchange,提问作者User128912
相关产品推荐
相关产品推荐

