diff --git a/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs b/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs index e3f966eebb2..8bf65a9c400 100644 --- a/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs +++ b/crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs @@ -2,6 +2,12 @@ namespace SpacetimeDB.BSATN; using System.Text; +internal static class StructuralReadWrite + where T : IStructuralReadWrite, new() +{ + public static readonly System.Func Constructor = () => new T(); +} + public interface IStructuralReadWrite { void ReadFields(BinaryReader reader); @@ -11,10 +17,16 @@ public interface IStructuralReadWrite static T Read(BinaryReader reader) where T : IStructuralReadWrite, new() { - // TODO: use `RuntimeHelpers.GetUninitializedObject` as an optimisation here. - // We tried but couldn't do this because BitCraft relies on being able - // to add and initialize custom fields on autogenerated classes. - var result = new T(); + // Previously we attempted to use `GetUninitializedObject` as an optimisation here. + // This is because `new T()` can use reflection depending on the runtime, compiler, etc. + // And this is a cost that we must pay per deserialized row. + // Unfortunately BitCraft relies on being able to add and initialize custom fields on autogenerated classes. + // Therefore we couldn't use `GetUninitializedObject`. + // + // Instead we use a lambda inside a generic static class. + // Supposedly this always result in monomorphization. + // This may not be the case for generic methods depending on the runtime. + var result = StructuralReadWrite.Constructor(); result.ReadFields(reader); return result; }