Skip to content

Commit 85be484

Browse files
Avoid reflection when constructing row in bsatn deserialization
1 parent f11b814 commit 85be484

File tree

1 file changed

+16
-4
lines changed
  • crates/bindings-csharp/BSATN.Runtime/BSATN

1 file changed

+16
-4
lines changed

crates/bindings-csharp/BSATN.Runtime/BSATN/Runtime.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@ namespace SpacetimeDB.BSATN;
22

33
using System.Text;
44

5+
internal static class StructuralReadWrite<T>
6+
where T : IStructuralReadWrite, new()
7+
{
8+
public static readonly System.Func<T> Constructor = () => new T();
9+
}
10+
511
public interface IStructuralReadWrite
612
{
713
void ReadFields(BinaryReader reader);
@@ -11,10 +17,16 @@ public interface IStructuralReadWrite
1117
static T Read<T>(BinaryReader reader)
1218
where T : IStructuralReadWrite, new()
1319
{
14-
// TODO: use `RuntimeHelpers.GetUninitializedObject` as an optimisation here.
15-
// We tried but couldn't do this because BitCraft relies on being able
16-
// to add and initialize custom fields on autogenerated classes.
17-
var result = new T();
20+
// Previously we attempted to use `GetUninitializedObject` as an optimisation here.
21+
// This is because `new T()` can use reflection depending on the runtime, compiler, etc.
22+
// And this is a cost that we must pay per deserialized row.
23+
// Unfortunately BitCraft relies on being able to add and initialize custom fields on autogenerated classes.
24+
// Therefore we couldn't use `GetUninitializedObject`.
25+
//
26+
// Instead we use a lambda inside a generic static class.
27+
// Supposedly this always result in monomorphization.
28+
// This may not be the case for generic methods depending on the runtime.
29+
var result = StructuralReadWrite<T>.Constructor();
1830
result.ReadFields(reader);
1931
return result;
2032
}

0 commit comments

Comments
 (0)