使用CSVHelper ClassMap导出含Vector3的自定义类到CSV映射异常
Unity Vector3导出CSV时CSVHelper映射异常问题解决
问题描述
将包含Unity Vector3对象的自定义BehaviouralData类数据导出到CSV时,已创建Vector3Map并注册,但运行时抛出ArgumentException,且CSV列包含magnitude等非预期属性,而非x/y/z坐标。
相关代码
自定义BehaviouralData类
public class BehaviouralData { public float ActionZ { get; set; } public float ActionX { get; set; } public int TargetBallAgentHashCode { get; set; } public Vector3 TargetBallLocalPosition { get; set; } public bool CollectBehaviouralData { get; set; } public DateTime ActionTime { get; set; } public DateTime Time { get; set; } }
Vector3Map类
public sealed class Vector3Map : ClassMap<Vector3> { public Vector3Map() { Map(m => m.x); Map(m => m.y); Map(m => m.z); } }
注册及写入代码
... using (var csv = new CsvWriter(writer, config)) { csv.Context.RegisterClassMap<Vector3Map>(); csv.WriteRecords(data); } ...
错误信息
ArgumentException: Incorrect number of arguments supplied for call to method 'Single get_Item(Int32)'...
生成的CSV列:
ActionZ,ActionX,TargetBallAgentHashCode,Item,Item,magnitude,sqrMagnitude,magnitude,sqrMagnitude,CollectBehaviouralData,ActionTime,Time
问题原因
- 未关联父类与子对象映射:仅注册Vector3Map不会让CSVHelper自动在处理BehaviouralData的Vector3属性时使用该映射,CSVHelper默认会遍历Vector3的所有公共成员(包括索引器
Item、magnitude等属性),导致生成非预期列并触发索引器调用错误。 - Unity Vector3的结构特性:Vector3是结构体,包含带参数的索引器
this[int],CSVHelper尝试访问该索引器时因缺少参数抛出异常。
解决方法
方法1:为BehaviouralData创建显式ClassMap并关联Vector3Map
创建BehaviouralData的ClassMap,明确指定TargetBallLocalPosition使用已定义的Vector3Map:
public sealed class BehaviouralDataMap : ClassMap<BehaviouralData> { public BehaviouralDataMap() { Map(m => m.ActionZ); Map(m => m.ActionX); Map(m => m.TargetBallAgentHashCode); // 关联Vector3Map到目标属性 Map(m => m.TargetBallLocalPosition).MapType<Vector3Map>(); Map(m => m.CollectBehaviouralData); Map(m => m.ActionTime); Map(m => m.Time); } }
写入时注册两个ClassMap:
... using (var csv = new CsvWriter(writer, config)) { csv.Context.RegisterClassMap<BehaviouralDataMap>(); csv.Context.RegisterClassMap<Vector3Map>(); csv.WriteRecords(data); } ...
方法2:禁用自动映射,强制使用显式配置
通过CSVConfiguration禁用自动映射,确保仅使用自定义的ClassMap:
var config = new CsvConfiguration(CultureInfo.InvariantCulture) { AutoMap = false, // 禁用自动映射 }; using (var csv = new CsvWriter(writer, config)) { csv.Context.RegisterClassMap<BehaviouralDataMap>(); csv.Context.RegisterClassMap<Vector3Map>(); csv.WriteRecords(data); }
方法3:直接扩展Vector3分量属性(无需映射)
在BehaviouralData中添加对应Vector3分量的只读属性,直接导出这些属性:
public class BehaviouralData { // 原有属性... public Vector3 TargetBallLocalPosition { get; set; } // 添加Vector3分量属性 public float TargetBallPosX => TargetBallLocalPosition.x; public float TargetBallPosY => TargetBallLocalPosition.y; public float TargetBallPosZ => TargetBallLocalPosition.z; // 原有属性... }
此时导出会直接生成TargetBallPosX/TargetBallPosY/TargetBallPosZ列,无需处理Vector3的映射逻辑。
内容的提问来源于stack exchange,提问作者Ling
相关产品推荐
相关产品推荐

