如何将Object转换为泛型List<T>并作为Func输入参数传入?
问题描述
我定义了一套Operator类体系,其中SingleOperand<T,O>包含Func<T,O>类型的Function成员。当T是int、float或string这类简单类型时,能直接把object转换为对应类型后调用Function;但当T是泛型List类型时,不知道如何将输入的object(比如List<int>或List<object>)转换为目标List<TElement>类型(比如List<float>)。目前只有完全匹配的测试用例能通过,需要实现可转换列表的类型适配功能。
原实现代码
using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace GameToolkit.Operator { public abstract class IOperator { public abstract Type OutputType { get; } public abstract Type[] GetInputTypes(); public abstract object GetValue(object a); public ValueToken GetValues(object a) { var v = GetValue(a); return new ValueToken() { Type = v.GetType(), Value = v }; } } public class SingleOperand<T, O> : IOperator { public Func<T, O> Function { get; set; } public SingleOperand() { } public SingleOperand(Func<T, O> function) { Function = function; } public override object GetValue(object a) { if (Function == null) return default(T); if (a.GetType().IsGenericType) { ///SOME CODE HERE!!! } else return Function((T)a); } public override Type OutputType => typeof(O); public override Type[] GetInputTypes() { return new[] { typeof(T) }; } } }
测试场景
[Test] public void UTValueExpressions1() { var a = new SingleOperand<List<float>, bool>((b)=>{return b.Count > 0;}); a.GetValue(new List<float>{1,2}); } [Test] public void UTValueExpressions2() { var a = new SingleOperand<List<float>, bool>((b)=>{return b.Count > 0;}); a.GetValue(new List<int>{1,2}); } [Test] public void UTValueExpressions3() { var a = new SingleOperand<List<float>, bool>((b)=>{return b.Count > 0;}); a.GetValue(new List<object>{1,2}); }
目前仅UTValueExpressions1能通过,需要让后两个测试也正常执行,实现将List<int>/List<object>转换为List<float>的功能(元素可转换时)。
解决方案
修改SingleOperand<T,O>的GetValue方法,通过反射识别目标List的元素类型,遍历输入集合的每个元素尝试转换,最终构建目标类型的List实例:
public override object GetValue(object a) { if (Function == null) return default(T); // 优先尝试直接转换,适配简单类型和完全匹配的List场景 try { return Function((T)a); } catch (InvalidCastException) { var targetType = typeof(T); // 检查目标类型是否为List<> if (targetType.IsGenericType && targetType.GetGenericTypeDefinition() == typeof(List<>)) { var targetElementType = targetType.GetGenericArguments()[0]; // 检查输入对象是否为可枚举类型 if (a is IEnumerable inputEnumerable) { // 创建目标类型的List实例 var targetList = Activator.CreateInstance(targetType) as IList; foreach (var item in inputEnumerable) { try { // 尝试将元素转换为目标元素类型 var convertedItem = Convert.ChangeType(item, targetElementType); targetList?.Add(convertedItem); } catch (InvalidCastException) { throw new InvalidCastException($"无法将元素 {item} 转换为类型 {targetElementType}"); } } // 将转换后的List传入Function执行 return Function((T)(object)targetList); } } // 其他无法处理的转换情况,抛出原异常 throw; } }
代码说明
- 优先直接转换:先尝试强转,兼容原有简单类型和完全匹配的List场景,减少反射开销。
- 反射识别List类型:直接转换失败时,检查目标类型
T是否为List<>,提取其元素类型。 - 元素逐个转换:将输入的可枚举对象逐个元素转换为目标类型,构建目标
List实例。 - 异常处理:元素转换失败时抛出明确异常,也可根据业务需求改为跳过无效元素。
测试验证
修改后三个测试用例均可正常通过:
UTValueExpressions1:类型完全匹配,直接执行。UTValueExpressions2:List<int>的每个元素转换为float,构建List<float>后传入Function。UTValueExpressions3:List<object>中的整数元素转换为float,构建List<float>后传入Function。
内容的提问来源于stack exchange,提问作者NSediq
相关产品推荐
相关产品推荐

