PropertyInfo.GetValue抛出TargetException:对象与目标类型不匹配
我想要读取每一行row的所有值,代码实现如下:
internal class ExcelTable<T> : IExcelTable where T : IExcelTableRow { void Foo(){ var props = typeof(T).GetProperties().ToList(); for (int r = 0; r < Rows.Count; r++) { IExcelTableRow row = Rows[r]; foreach (var p in props) { // 第一个属性{Int32 Id}时抛出错误 var v = p.GetValue(row); } } } }
运行时抛出以下错误:
System.Reflection.TargetException: 'Object does not match target type.'
当前T的实际类型为ExcelTranscationLogRow(实现了IExcelTableRow接口),该类定义如下:
internal class ExcelTranscationLogRow : IExcelTableRow { public int Id { get; set; } // 3619 public TransactionType TransactionType { get; set; }// TransactionType.Execution public string Identifier { get; set; } // "Placeholder" public TransactionStatus Status { get; set; } // LogType.Success public LogType LogType { get; set; } // TransactionStatus.Trace public string Log { get; set; } // "Getting KOT and CPR" public DateTime TimeStamp { get; set; } // {05-07-2022 19:06:38} }
但另一个IExcelTableRow的实现类ExcelTransactionRow却能正常运行:
internal class ExcelTransactionRow : IExcelTableRow { public int Id { get; set; } public string Identifier { get; set; } public TransactionStatus Status { get; set; } public DateTime StartTime { get; set; } public DateTime? EndTime { get; set; } }
问题根源
错误核心是反射使用的属性信息(来自T类型)与传入的目标对象类型不匹配:
你通过typeof(T).GetProperties()获取了T(如ExcelTranscationLogRow)的属性信息,但代码中row被声明为IExcelTableRow接口类型,且Rows集合可能混入了非T类型的实例;或者T被错误指定为IExcelTableRow接口而非具体实现类,导致反射逻辑混乱。
具体修复方案
1. 强制将行转换为T类型
在读取行时,直接将IExcelTableRow类型的对象转换为泛型参数T,确保目标对象类型与反射使用的属性信息所属类型一致:
void Foo(){ var props = typeof(T).GetProperties().ToList(); for (int r = 0; r < Rows.Count; r++) { // 转换为T类型,确保类型匹配 T row = (T)Rows[r]; foreach (var p in props) { var v = p.GetValue(row); } } }
2. 修正Rows集合的类型
将Rows的类型从List<IExcelTableRow>改为List<T>,这样从集合中取出的元素直接是T类型,从根源避免类型不匹配问题:
internal class ExcelTable<T> : IExcelTable where T : IExcelTableRow { // 将Rows改为List<T>类型 public List<T> Rows { get; set; } void Foo(){ var props = typeof(T).GetProperties().ToList(); for (int r = 0; r < Rows.Count; r++) { T row = Rows[r]; foreach (var p in props) { var v = p.GetValue(row); } } } }
3. 确认泛型参数的正确性
实例化ExcelTable<T>时,确保传入的泛型参数是具体的实现类(如ExcelTranscationLogRow),而非IExcelTableRow接口。如果传入接口类型,typeof(T).GetProperties()只能获取接口定义的属性,无法访问具体类的扩展属性,会导致反射逻辑不符合预期。
内容的提问来源于stack exchange,提问作者Theodor349

