Skip to content

Commit 6fb1e84

Browse files
fix(generator): replace C# 10 inferred delegates with direct method calls for C# 9 compatibility
Generated code was using C# 10 "inferred delegate type" feature (var = method group) which is incompatible with Unity's C# 9.0 support. This caused CS8773 errors when building in Unity environments. Changes: - ArrayGenerator: Removed delegate variable declarations in monomorphic paths - Replace indirect delegate calls with direct CachedSerializer/CachedDeserializer method calls - Fixes serializer, deserializer (out), and deserializer (ref) code paths Benefits: - C# 9.0 compatible for Unity environments - Zero delegate allocation overhead (performance improvement) - Better JIT inlining potential with direct calls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent f76491f commit 6fb1e84

File tree

1 file changed

+8
-28
lines changed

1 file changed

+8
-28
lines changed

src/Nino.Generator/BuiltInType/ArrayGenerator.cs

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,6 @@ protected override void GenerateSerializer(ITypeSymbol typeSymbol, Writer writer
9595
writer.AppendLine(" }");
9696
writer.AppendLine();
9797

98-
// Monomorphic fast path: cache the serializer delegate once
99-
if (canUseMonomorphicPath)
100-
{
101-
writer.AppendLine(" // Monomorphic fast path: element type is sealed/struct, cache serializer");
102-
writer.AppendLine($" var serializer = CachedSerializer<{elementType.GetDisplayString()}>.SerializePolymorphic;");
103-
writer.AppendLine();
104-
}
105-
10698
// Both value and reference types benefit from ref iteration - eliminates bounds checks
10799
writer.AppendLine("#if NET5_0_OR_GREATER");
108100
writer.AppendLine(" ref var cur = ref System.Runtime.InteropServices.MemoryMarshal.GetArrayDataReference(value);");
@@ -118,8 +110,8 @@ protected override void GenerateSerializer(ITypeSymbol typeSymbol, Writer writer
118110

119111
if (canUseMonomorphicPath)
120112
{
121-
// Use cached serializer directly
122-
writer.AppendLine(" serializer(cur, ref writer);");
113+
// Monomorphic fast path: direct call to avoid delegate allocation
114+
writer.AppendLine($" CachedSerializer<{elementType.GetDisplayString()}>.SerializePolymorphic(cur, ref writer);");
123115
}
124116
else
125117
{
@@ -258,27 +250,21 @@ protected override void GenerateDeserializer(ITypeSymbol typeSymbol, Writer writ
258250
writer.AppendLine(";");
259251
writer.AppendLine(" var span = value.AsSpan();");
260252

261-
// Monomorphic fast path: cache the deserializer delegate once
262-
if (canUseMonomorphicPath)
263-
{
264-
writer.AppendLine(" // Monomorphic fast path: element type is sealed/struct, cache deserializer");
265-
writer.AppendLine($" var deserializer = CachedDeserializer<{elementType.GetDisplayString()}>.Deserialize;");
266-
}
267-
268253
writer.AppendLine(" for (int i = 0; i < length; i++)");
269254
writer.AppendLine(" {");
270255

271256
if (canUseMonomorphicPath)
272257
{
258+
// Monomorphic fast path: direct call to avoid delegate allocation
273259
IfElseDirective(NinoTypeHelper.WeakVersionToleranceSymbol, writer,
274260
w =>
275261
{
276262
w.AppendLine(" eleReader = reader.Slice();");
277-
w.AppendLine(" deserializer(out span[i], ref eleReader);");
263+
w.AppendLine($" CachedDeserializer<{elementType.GetDisplayString()}>.Deserialize(out span[i], ref eleReader);");
278264
},
279265
w =>
280266
{
281-
w.AppendLine(" deserializer(out span[i], ref reader);");
267+
w.AppendLine($" CachedDeserializer<{elementType.GetDisplayString()}>.Deserialize(out span[i], ref reader);");
282268
});
283269
}
284270
else
@@ -429,27 +415,21 @@ protected override void GenerateDeserializer(ITypeSymbol typeSymbol, Writer writ
429415
writer.AppendLine();
430416
writer.AppendLine(" var span = value.AsSpan();");
431417

432-
// Monomorphic fast path: cache the deserializer delegate once
433-
if (canUseMonomorphicPath)
434-
{
435-
writer.AppendLine(" // Monomorphic fast path: element type is sealed/struct, cache deserializer");
436-
writer.AppendLine($" var deserializerRef = CachedDeserializer<{elementType.GetDisplayString()}>.DeserializeRef;");
437-
}
438-
439418
writer.AppendLine(" for (int i = 0; i < length; i++)");
440419
writer.AppendLine(" {");
441420

442421
if (canUseMonomorphicPath)
443422
{
423+
// Monomorphic fast path: direct call to avoid delegate allocation
444424
IfElseDirective(NinoTypeHelper.WeakVersionToleranceSymbol, writer,
445425
w =>
446426
{
447427
w.AppendLine(" eleReader = reader.Slice();");
448-
w.AppendLine(" deserializerRef(ref span[i], ref eleReader);");
428+
w.AppendLine($" CachedDeserializer<{elementType.GetDisplayString()}>.DeserializeRef(ref span[i], ref eleReader);");
449429
},
450430
w =>
451431
{
452-
w.AppendLine(" deserializerRef(ref span[i], ref reader);");
432+
w.AppendLine($" CachedDeserializer<{elementType.GetDisplayString()}>.DeserializeRef(ref span[i], ref reader);");
453433
});
454434
}
455435
else

0 commit comments

Comments
 (0)