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 static partial class CsvExtensions
public static ClassMap UpdateReferenceMaps<TReferenceMap, TReferenceClass>(this ClassMap classMap, params object[] constructorArgs) where TReferenceMap : ClassMap<TReferenceClass>
for (int i = classMap.ReferenceMaps.Count - 1; i >= 0; i--)
var oldRef = classMap.ReferenceMaps[i];
var memberType = oldRef.Data.Member.MemberType();
if (memberType == typeof(TReferenceClass))
classMap.ReferenceMaps.RemoveAt(i);
Console.WriteLine("Removed at {0} for {1}", i, oldRef.Data.Member);
var newRef = classMap.References(typeof(TReferenceMap), oldRef.Data.Member, constructorArgs);
var newIndex = classMap.ReferenceMaps.IndexOfWithHint(newRef, classMap.ReferenceMaps.Count - 1);
classMap.ReferenceMaps.RemoveAt(newIndex);
classMap.ReferenceMaps.Insert(i, newRef);
if (oldRef.Data.Prefix != null)
newRef.Prefix(oldRef.Data.Prefix);
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);
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; }
public sealed class Vector3Map : ClassMap<Vector3>
public class DefaultAutoMap<TClass> : ClassMap<TClass>
AutoMap(CultureInfo.InvariantCulture);
this.UpdateReferenceMaps<Vector3Map, Vector3>();
public class BehaviouralDataMapExplicit : ClassMap<BehaviouralData>
public BehaviouralDataMapExplicit()
Map(m => m.TargetBallAgentHashCode);
References(typeof(Vector3Map), typeof(BehaviouralData).GetProperty(nameof(BehaviouralData.TargetBallLocalPosition)));
Map(m => m.CollectBehaviouralData);
this.UpdateReferenceMaps<Vector3Map, Vector3>();
public static void Test()
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 }},
var config = new CsvConfiguration(CultureInfo.InvariantCulture);
using var writer = new StringWriter();
using (var csv = new CsvWriter(writer, config))
csv.Context.RegisterClassMap<DefaultAutoMap<BehaviouralData>>();
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 x { get; set; }
public float y { get; set; }
public float z { get; set; }
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)