using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Collections.ObjectModel;
using CsvHelper.Configuration;
using CsvHelper.Configuration.Attributes;
using CsvHelper.Expressions;
using CsvHelper.TypeConversion;
public class CustomAutoMap<TClass> : ClassMap<TClass>
AutoMap(CultureInfo.InvariantCulture);
this.UpdateReferences<Vector3Map, Vector3>();
public static partial class CsvExtensions
public static ClassMap UpdateReferences<TReferenceMap, TReferenceClass>(this ClassMap classMap, params object[] constructorArgs) where TReferenceMap : ClassMap<TReferenceClass>
for (int i = 0, count = classMap.ReferenceMaps.Count; i < count; i++)
if (classMap.ReferenceMaps[i].Data.Member.MemberType() == typeof(TReferenceClass))
classMap.UpdateReference<TReferenceMap, TReferenceClass>(i, constructorArgs);
public static MemberReferenceMap UpdateReference<TReferenceMap, TReferenceClass>(this ClassMap classMap, int index, params object[] constructorArgs) where TReferenceMap : ClassMap<TReferenceClass>
if (index < 0 || index >= classMap.ReferenceMaps.Count)
throw new ArgumentException(nameof(index));
var oldRef = classMap.ReferenceMaps[index];
classMap.ReferenceMaps.RemoveAt(index);
var newRef = classMap.References(typeof(TReferenceMap), oldRef.Data.Member, constructorArgs);
if (oldRef.Data.Prefix != null)
newRef.Prefix(oldRef.Data.Prefix);
classMap.ReferenceMaps.Swap(index, classMap.ReferenceMaps.IndexOfWithHint(newRef, classMap.ReferenceMaps.Count - 1));
static Type? MemberType(this MemberInfo m) =>
PropertyInfo p => p.PropertyType,
FieldInfo f => f.FieldType,
static int IndexOfWithHint<T>(this IList<T> list, T item, int hint) where T : class
if (hint >= 0 && hint < list.Count && list[hint] == item)
return list.IndexOf(item);
static void Swap<T>(this IList<T> list, int i, int j)
public class BehaviouralData
public float ActionZ { get; set; }
public float ActionX { get; set; }
public int TargetBallAgentHashCode { get; set; }
[CsvHelper.Configuration.Attributes.HeaderPrefix("TargetBallLocation_")]
public Vector3 TargetBallLocalPosition { get; set; }
public bool CollectBehaviouralData { get; set; }
public DateTime ActionTime { get; set; }
public DateTime Time { get; set; }
public sealed class Vector3Map : ClassMap<Vector3>
public class BehaviouralDataMapExplicit : ClassMap<BehaviouralData>
public BehaviouralDataMapExplicit()
Map(m => m.TargetBallAgentHashCode);
References<Vector3Map>(m => m.TargetBallLocalPosition)
.Prefix("TargetBallLocation_");
Map(m => m.CollectBehaviouralData);
public static void Test()
static void TestAutoMap()
Console.WriteLine("\nTesting DefaultAutoMap<BehaviouralData>:");
var data = new List<BehaviouralData>()
new() { TargetBallAgentHashCode = 1, TargetBallLocalPosition = new() { x = 1.1f, y = 1.1f, z = 1.1f }},
new() { TargetBallAgentHashCode = 2, TargetBallLocalPosition = new() { x = 2.1f, y = 2.1f, z = 2.1f }},
new() { TargetBallAgentHashCode = 3, TargetBallLocalPosition = new() { x = 3.1f, y = 3.1f, z = 3.1f }},
using var writer = new StringWriter();
var config = new CsvConfiguration(CultureInfo.InvariantCulture);
using (var csv = new CsvWriter(writer, config))
csv.Context.RegisterClassMap<CustomAutoMap<BehaviouralData>>();
Console.WriteLine(writer);
static void TestExplicitMap()
Console.WriteLine("\nTesting BehaviouralDataMapExplicit:");
var data = new List<BehaviouralData>()
new() { TargetBallAgentHashCode = 1, TargetBallLocalPosition = new() { x = 1.1f, y = 1.1f, z = 1.1f }},
new() { TargetBallAgentHashCode = 2, TargetBallLocalPosition = new() { x = 2.1f, y = 2.1f, z = 2.1f }},
new() { TargetBallAgentHashCode = 3, TargetBallLocalPosition = new() { x = 3.1f, y = 3.1f, z = 3.1f }},
using var writer = new StringWriter();
var config = new CsvConfiguration(CultureInfo.InvariantCulture);
using (var csv = new CsvWriter(writer, config))
csv.Context.RegisterClassMap<BehaviouralDataMapExplicit>();
Console.WriteLine(writer);
public static void Main()
Console.WriteLine("Environment version: {0} ({1}), {2}.", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
Console.WriteLine("OS Version: {0}, NewLine: {1}", System.Environment.OSVersion, JsonConvert.SerializeObject(Environment.NewLine));
Console.WriteLine("{0} version: {1}", typeof(CsvReader).Assembly.GetName().Name, typeof(CsvReader).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public partial struct Vector3 : IEquatable<Vector3>
public const float kEpsilon = 0.00001F;
public const float kEpsilonNormalSqrt = 1e-15F;
public float this[int index]
throw new IndexOutOfRangeException("Invalid Vector3 index!");
throw new IndexOutOfRangeException("Invalid Vector3 index!");
public Vector3(float x, float y, float z)
public override int GetHashCode()
return x.GetHashCode() ^ (y.GetHashCode() << 2) ^ (z.GetHashCode() >> 2);
public override bool Equals(object other)
return Equals((Vector3)other);
public bool Equals(Vector3 other)
return x == other.x && y == other.y && z == other.z;
public static Vector3 Normalize(Vector3 value)
float mag = Magnitude(value);
float mag = Magnitude(this);
public Vector3 normalized
return Vector3.Normalize(this);
public static float Dot(Vector3 lhs, Vector3 rhs)
return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
public static float Magnitude(Vector3 vector)
return (float)Math.Sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
return (float)Math.Sqrt(x * x + y * y + z * z);
public static float SqrMagnitude(Vector3 vector)
return vector.x * vector.x + vector.y * vector.y + vector.z * vector.z;
public float sqrMagnitude
return x * x + y * y + z * z;
static readonly Vector3 zeroVector = new Vector3(0F, 0F, 0F);
static readonly Vector3 oneVector = new Vector3(1F, 1F, 1F);
static readonly Vector3 upVector = new Vector3(0F, 1F, 0F);
static readonly Vector3 downVector = new Vector3(0F, -1F, 0F);
static readonly Vector3 leftVector = new Vector3(-1F, 0F, 0F);
static readonly Vector3 rightVector = new Vector3(1F, 0F, 0F);
static readonly Vector3 forwardVector = new Vector3(0F, 0F, 1F);
static readonly Vector3 backVector = new Vector3(0F, 0F, -1F);
static readonly Vector3 positiveInfinityVector = new Vector3(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
static readonly Vector3 negativeInfinityVector = new Vector3(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity);
public static Vector3 zero
public static Vector3 one
public static Vector3 forward
public static Vector3 back
public static Vector3 down
public static Vector3 left
public static Vector3 right
public static Vector3 positiveInfinity
return positiveInfinityVector;
public static Vector3 negativeInfinity
return negativeInfinityVector;
public static Vector3 operator +(Vector3 a, Vector3 b)
return new Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
public static Vector3 operator -(Vector3 a, Vector3 b)
return new Vector3(a.x - b.x, a.y - b.y, a.z - b.z);
public static Vector3 operator -(Vector3 a)
return new Vector3(-a.x, -a.y, -a.z);
public static Vector3 operator *(Vector3 a, float d)
return new Vector3(a.x * d, a.y * d, a.z * d);
public static Vector3 operator *(float d, Vector3 a)
return new Vector3(a.x * d, a.y * d, a.z * d);
public static Vector3 operator /(Vector3 a, float d)
return new Vector3(a.x / d, a.y / d, a.z / d);
public static bool operator ==(Vector3 lhs, Vector3 rhs)
float diff_x = lhs.x - rhs.x;
float diff_y = lhs.y - rhs.y;
float diff_z = lhs.z - rhs.z;
float sqrmag = diff_x * diff_x + diff_y * diff_y + diff_z * diff_z;
return sqrmag < kEpsilon * kEpsilon;
public static bool operator !=(Vector3 lhs, Vector3 rhs)