diff --git a/AyCode.Core.Serializers.Console/Program.cs b/AyCode.Core.Serializers.Console/Program.cs
index a7b1e34..5a600a6 100644
--- a/AyCode.Core.Serializers.Console/Program.cs
+++ b/AyCode.Core.Serializers.Console/Program.cs
@@ -73,7 +73,7 @@ public static class Program
foreach (var testData in testDataSets)
{
System.Console.WriteLine($"\n{'═'.ToString().PadRight(70, '═')}");
- System.Console.WriteLine($"TEST DATA: {testData.Name}");
+ System.Console.WriteLine($"TEST DATA: {testData.DisplayName}");
System.Console.WriteLine($"{'═'.ToString().PadRight(70, '═')}");
var results = RunBenchmarksForTestData(testData, mode);
@@ -83,6 +83,8 @@ public static class Program
// Print grouped results
PrintGroupedResults(allResults, testDataSets);
+
+
// Save results to file
SaveResults(allResults, testDataSets);
@@ -106,21 +108,43 @@ public static class Program
private static TestDataSet CreateSmallTestData()
{
TestDataFactory.ResetIdCounter();
+
+ // Create shared references - IId types (only at Order/Item level)
+ var sharedTag = TestDataFactory.CreateTag("SharedTag");
+ var sharedUser = TestDataFactory.CreateUser("shareduser");
+
var order = TestDataFactory.CreateOrder(
itemCount: 2,
palletsPerItem: 2,
measurementsPerPallet: 2,
- pointsPerMeasurement: 2);
+ pointsPerMeasurement: 2,
+ sharedTag: sharedTag,
+ sharedUser: sharedUser);
- return new TestDataSet("Small (2x2x2x2)", order);
+ // Clear deeper level refs for realistic ~10% ratio
+ ClearDeepLevelRefs(order);
+
+ return new TestDataSet("Small (2x2x2x2)", order, iidRefPercent: 10);
}
private static TestDataSet CreateMediumTestData()
{
TestDataFactory.ResetIdCounter();
+
+ // IId shared references
var sharedTag = TestDataFactory.CreateTag("SharedTag");
var sharedUser = TestDataFactory.CreateUser("shareduser");
var sharedMeta = TestDataFactory.CreateMetadata("shared", withChild: true);
+
+ // Non-IId shared reference - create separate preferences for 2 users
+ var sharedPreferences = new UserPreferences
+ {
+ Theme = "dark",
+ Language = "en-US",
+ NotificationsEnabled = true,
+ EmailDigestFrequency = "weekly"
+ };
+ sharedUser.Preferences = sharedPreferences;
var order = TestDataFactory.CreateOrder(
itemCount: 3,
@@ -129,16 +153,32 @@ public static class Program
pointsPerMeasurement: 4,
sharedTag: sharedTag,
sharedUser: sharedUser,
- sharedMetadata: sharedMeta);
+ sharedMetadata: sharedMeta,
+ sharedPreferences: sharedPreferences);
- return new TestDataSet("Medium (3x3x3x4, shared refs)", order);
+ // Clear deeper level refs for realistic ~10% ratio
+ ClearDeepLevelRefs(order);
+
+ return new TestDataSet("Medium (3x3x3x4)", order, iidRefPercent: 10);
}
private static TestDataSet CreateLargeTestData()
{
TestDataFactory.ResetIdCounter();
+
+ // IId shared references
var sharedTag = TestDataFactory.CreateTag("SharedTag");
var sharedUser = TestDataFactory.CreateUser("shareduser");
+
+ // Non-IId shared reference
+ var sharedPreferences = new UserPreferences
+ {
+ Theme = "light",
+ Language = "de-DE",
+ NotificationsEnabled = false,
+ EmailDigestFrequency = "daily"
+ };
+ sharedUser.Preferences = sharedPreferences;
var order = TestDataFactory.CreateOrder(
itemCount: 5,
@@ -146,20 +186,42 @@ public static class Program
measurementsPerPallet: 5,
pointsPerMeasurement: 10,
sharedTag: sharedTag,
- sharedUser: sharedUser);
+ sharedUser: sharedUser,
+ sharedPreferences: sharedPreferences);
- return new TestDataSet("Large (5x5x5x10)", order);
+ // Clear deeper level refs for realistic ~10% ratio
+ ClearDeepLevelRefs(order);
+
+ return new TestDataSet("Large (5x5x5x10)", order, iidRefPercent: 10);
}
private static TestDataSet CreateRepeatedStringsTestData()
{
TestDataFactory.ResetIdCounter();
+
+ // IId shared references
+ var sharedTag = TestDataFactory.CreateTag("RepeatedTag");
+ var sharedUser = TestDataFactory.CreateUser("repeateduser");
+
+ // Non-IId shared reference
+ var sharedPreferences = new UserPreferences
+ {
+ Theme = "dark",
+ Language = "en-US",
+ NotificationsEnabled = true,
+ EmailDigestFrequency = "weekly"
+ };
+ sharedUser.Preferences = sharedPreferences;
+
// Create order with many items to test string interning on repeated property names
var order = TestDataFactory.CreateOrder(
itemCount: 10,
palletsPerItem: 2,
measurementsPerPallet: 2,
- pointsPerMeasurement: 2);
+ pointsPerMeasurement: 2,
+ sharedTag: sharedTag,
+ sharedUser: sharedUser,
+ sharedPreferences: sharedPreferences);
// Set same status and ProductName on all items to test enum and string handling
foreach (var item in order.Items)
@@ -167,20 +229,80 @@ public static class Program
item.Status = TestStatus.Processing;
item.ProductName = "CommonProductName_RepeatedForTesting";
}
+
+ // Clear deeper level refs for realistic ~10% ratio
+ ClearDeepLevelRefs(order);
- return new TestDataSet("Repeated Strings (10 items)", order);
+ return new TestDataSet("Repeated Strings (10 items)", order, iidRefPercent: 10);
}
+
+ ///
+ /// Clears IId shared references from Pallet, Measurement, and Point levels.
+ /// This creates a realistic ~10% IId ref ratio (only Order and Item levels have refs).
+ ///
+ private static void ClearDeepLevelRefs(TestOrder order)
+ {
+ foreach (var item in order.Items)
+ {
+ foreach (var pallet in item.Pallets)
+ {
+ pallet.Tag = null;
+ pallet.Inspector = null;
+ pallet.Category = null;
+
+ foreach (var measurement in pallet.Measurements)
+ {
+ measurement.Tag = null;
+ measurement.Operator = null;
+
+ foreach (var point in measurement.Points)
+ {
+ point.Tag = null;
+ point.Verifier = null;
+ }
+ }
+ }
+ }
+ }
+
+
+
+
+
private static TestDataSet CreateDeepNestedTestData()
{
TestDataFactory.ResetIdCounter();
+
+ // IId shared references - only at Order and Item levels for ~10% ratio
+ var sharedTag = TestDataFactory.CreateTag("DeepTag");
+ var sharedUser = TestDataFactory.CreateUser("deepuser");
+ var sharedCategory = TestDataFactory.CreateCategory("DeepCategory");
+
+ // Non-IId shared reference
+ var sharedPreferences = new UserPreferences
+ {
+ Theme = "light",
+ Language = "fr-FR",
+ NotificationsEnabled = false,
+ EmailDigestFrequency = "monthly"
+ };
+ sharedUser.Preferences = sharedPreferences;
+
var order = TestDataFactory.CreateOrder(
itemCount: 2,
palletsPerItem: 4,
measurementsPerPallet: 4,
- pointsPerMeasurement: 8);
+ pointsPerMeasurement: 8,
+ sharedTag: sharedTag,
+ sharedUser: sharedUser,
+ sharedPreferences: sharedPreferences,
+ sharedCategory: sharedCategory);
+
+ // Clear deeper level refs for realistic ~10% ratio
+ ClearDeepLevelRefs(order);
- return new TestDataSet("Deep Nested (2x4x4x8)", order);
+ return new TestDataSet("Deep Nested (2x4x4x8)", order, iidRefPercent: 10);
}
#endregion
@@ -206,7 +328,7 @@ public static class Program
{
var result = new BenchmarkResult
{
- TestDataName = testData.Name,
+ TestDataName = testData.DisplayName, // Use DisplayName for IId% info
SerializerName = serializer.Name,
SerializedSize = serializer.SerializedSize
};
@@ -464,14 +586,30 @@ public static class Program
{
public string Name { get; }
public TestOrder Order { get; }
+
+ ///
+ /// Percentage of IId shared references in the data (0-100).
+ /// Higher values mean more deduplication benefit for Default mode.
+ ///
+ public int IIdRefPercent { get; }
- public TestDataSet(string name, TestOrder order)
+ public TestDataSet(string name, TestOrder order, int iidRefPercent = 0)
{
Name = name;
Order = order;
+ IIdRefPercent = iidRefPercent;
}
+
+ ///
+ /// Gets display name including IId ref percentage if set.
+ ///
+ public string DisplayName => IIdRefPercent > 0
+ ? $"{Name} [{IIdRefPercent}% IId refs]"
+ : Name;
}
+
+
private sealed class BenchmarkResult
{
public string TestDataName { get; set; } = "";
@@ -498,11 +636,11 @@ public static class Program
foreach (var testData in testDataSets)
{
- var testResults = results.Where(r => r.TestDataName == testData.Name).OrderBy(r => r.RoundTripTimeMs).ToList();
+ var testResults = results.Where(r => r.TestDataName == testData.DisplayName).OrderBy(r => r.RoundTripTimeMs).ToList();
var msgPackResult = testResults.FirstOrDefault(r => r.SerializerName == SerializerMessagePack);
var acBinaryResult = testResults.FirstOrDefault(r => r.SerializerName == SerializerAcBinaryDefault);
- System.Console.WriteLine($"\n┌─ {testData.Name} ─".PadRight(98, '─') + "┐");
+ System.Console.WriteLine($"\n┌─ {testData.DisplayName} ─".PadRight(98, '─') + "┐");
System.Console.WriteLine($"│ {"#",-4} │ {"Serializer",-25} │ {"Size",-10} │ {"Serialize",-12} │ {"Deserialize",-12} │ {"Round-trip",-12} │");
System.Console.WriteLine($"├{"─".PadRight(6, '─')}┼{"─".PadRight(27, '─')}┼{"─".PadRight(12, '─')}┼{"─".PadRight(14, '─')}┼{"─".PadRight(14, '─')}┼{"─".PadRight(14, '─')}┤");
diff --git a/AyCode.Core.Tests/Serialization/QuickBenchmark.cs b/AyCode.Core.Tests/Serialization/QuickBenchmark.cs
index 27031a5..b8054bb 100644
--- a/AyCode.Core.Tests/Serialization/QuickBenchmark.cs
+++ b/AyCode.Core.Tests/Serialization/QuickBenchmark.cs
@@ -402,7 +402,7 @@ public class QuickBenchmark
// Warmup
Console.WriteLine("\nWarming up...");
- for (int i = 0; i < 100; i++)
+ for (int i = 0; i < 10; i++)
{
_ = AcBinarySerializer.Serialize(testOrder, withRefOptions);
_ = AcBinarySerializer.Serialize(testOrder, noRefOptions);
diff --git a/AyCode.Core.Tests/TestModels/SharedTestModels.cs b/AyCode.Core.Tests/TestModels/SharedTestModels.cs
index e2c7077..c22959e 100644
--- a/AyCode.Core.Tests/TestModels/SharedTestModels.cs
+++ b/AyCode.Core.Tests/TestModels/SharedTestModels.cs
@@ -218,7 +218,12 @@ public class TestPallet : IId
// Level 4 collection
public List Measurements { get; set; } = [];
- // Shared references
+ // Shared IId references for better reference testing
+ public SharedTag? Tag { get; set; }
+ public SharedUser? Inspector { get; set; }
+ public SharedCategory? Category { get; set; }
+
+ // Non-IId shared references
public MetadataInfo? PalletMetadata { get; set; }
// Parent reference - ignored by all serializers to prevent circular references
@@ -242,6 +247,10 @@ public class TestMeasurement : IId
// Level 5 collection
public List Points { get; set; } = [];
+ // Shared IId references for better reference testing
+ public SharedTag? Tag { get; set; }
+ public SharedUser? Operator { get; set; }
+
// Parent reference - ignored by all serializers to prevent circular references
[JsonIgnore]
[IgnoreMember]
@@ -260,6 +269,10 @@ public class TestMeasurementPoint : IId
public double Value { get; set; }
public DateTime MeasuredAt { get; set; } = DateTime.UtcNow;
+ // Shared IId reference for better reference testing (many points share same tag/user)
+ public SharedTag? Tag { get; set; }
+ public SharedUser? Verifier { get; set; }
+
// Parent reference - ignored by all serializers to prevent circular references
[JsonIgnore]
[IgnoreMember]
diff --git a/AyCode.Core.Tests/TestModels/TestDataFactory.cs b/AyCode.Core.Tests/TestModels/TestDataFactory.cs
index 71f4b6c..028bf84 100644
--- a/AyCode.Core.Tests/TestModels/TestDataFactory.cs
+++ b/AyCode.Core.Tests/TestModels/TestDataFactory.cs
@@ -104,7 +104,8 @@ public static class TestDataFactory
#region Hierarchy Creation (5 Levels)
///
- /// Create a deep order hierarchy with configurable depth
+ /// Create a deep order hierarchy with configurable depth.
+ /// Supports both IId-based (SharedTag, SharedUser, SharedCategory) and Non-IId (UserPreferences) shared references.
///
public static TestOrder CreateOrder(
int itemCount = 2,
@@ -113,8 +114,13 @@ public static class TestDataFactory
int pointsPerMeasurement = 3,
SharedTag? sharedTag = null,
SharedUser? sharedUser = null,
- MetadataInfo? sharedMetadata = null)
+ MetadataInfo? sharedMetadata = null,
+ UserPreferences? sharedPreferences = null,
+ SharedCategory? sharedCategory = null)
{
+ // If sharedUser is provided but no sharedPreferences, use the user's preferences as shared
+ sharedPreferences ??= sharedUser?.Preferences;
+
var order = new TestOrder
{
Id = _idCounter++,
@@ -125,6 +131,7 @@ public static class TestDataFactory
PrimaryTag = sharedTag,
SecondaryTag = sharedTag, // Same reference for $ref testing
Owner = sharedUser,
+ Category = sharedCategory,
OrderMetadata = sharedMetadata,
AuditMetadata = sharedMetadata // Same reference for Newtonsoft $ref
};
@@ -136,7 +143,15 @@ public static class TestDataFactory
for (int i = 0; i < itemCount; i++)
{
- var item = CreateOrderItem(palletsPerItem, measurementsPerPallet, pointsPerMeasurement, sharedTag, sharedUser, sharedMetadata);
+ var item = CreateOrderItem(
+ palletsPerItem,
+ measurementsPerPallet,
+ pointsPerMeasurement,
+ sharedTag,
+ sharedUser,
+ sharedMetadata,
+ sharedPreferences,
+ sharedCategory);
item.ParentOrder = order;
order.Items.Add(item);
}
@@ -145,7 +160,8 @@ public static class TestDataFactory
}
///
- /// Create an order item with pallets
+ /// Create an order item with pallets.
+ /// Supports both IId-based and Non-IId shared references.
///
public static TestOrderItem CreateOrderItem(
int palletCount = 2,
@@ -153,8 +169,19 @@ public static class TestDataFactory
int pointsPerMeasurement = 3,
SharedTag? sharedTag = null,
SharedUser? sharedUser = null,
- MetadataInfo? sharedMetadata = null)
+ MetadataInfo? sharedMetadata = null,
+ UserPreferences? sharedPreferences = null,
+ SharedCategory? sharedCategory = null)
{
+ // Create assignee - if sharedUser provided, use it. Otherwise create new user with sharedPreferences
+ SharedUser? assignee = sharedUser;
+ if (assignee == null && sharedPreferences != null)
+ {
+ // Create a new user but with shared preferences (Non-IId ref testing)
+ assignee = CreateUser();
+ assignee.Preferences = sharedPreferences;
+ }
+
var item = new TestOrderItem
{
Id = _idCounter++,
@@ -163,13 +190,20 @@ public static class TestDataFactory
UnitPrice = 5.5m * _idCounter,
Status = TestStatus.Pending,
Tag = sharedTag,
- Assignee = sharedUser,
+ Assignee = assignee,
ItemMetadata = sharedMetadata
};
for (int i = 0; i < palletCount; i++)
{
- var pallet = CreatePallet(measurementsPerPallet, pointsPerMeasurement, sharedMetadata);
+ // Pass shared references to all levels - creates many shared refs!
+ var pallet = CreatePallet(
+ measurementsPerPallet,
+ pointsPerMeasurement,
+ sharedMetadata,
+ sharedTag, // IId shared ref
+ sharedUser, // IId shared ref
+ sharedCategory); // IId shared ref
pallet.ParentItem = item;
item.Pallets.Add(pallet);
}
@@ -177,13 +211,19 @@ public static class TestDataFactory
return item;
}
+
+
+
///
/// Create a pallet with measurements
///
public static TestPallet CreatePallet(
int measurementCount = 2,
int pointsPerMeasurement = 3,
- MetadataInfo? sharedMetadata = null)
+ MetadataInfo? sharedMetadata = null,
+ SharedTag? sharedTag = null,
+ SharedUser? sharedInspector = null,
+ SharedCategory? sharedCategory = null)
{
var pallet = new TestPallet
{
@@ -192,12 +232,15 @@ public static class TestDataFactory
TrayCount = 5 + _idCounter % 10,
Status = TestStatus.Pending,
Weight = 100.5 + _idCounter,
- PalletMetadata = sharedMetadata
+ PalletMetadata = sharedMetadata,
+ Tag = sharedTag,
+ Inspector = sharedInspector,
+ Category = sharedCategory
};
for (int i = 0; i < measurementCount; i++)
{
- var measurement = CreateMeasurement(pointsPerMeasurement);
+ var measurement = CreateMeasurement(pointsPerMeasurement, sharedTag, sharedInspector);
measurement.ParentPallet = pallet;
pallet.Measurements.Add(measurement);
}
@@ -208,19 +251,24 @@ public static class TestDataFactory
///
/// Create a measurement with points
///
- public static TestMeasurement CreateMeasurement(int pointCount = 3)
+ public static TestMeasurement CreateMeasurement(
+ int pointCount = 3,
+ SharedTag? sharedTag = null,
+ SharedUser? sharedOperator = null)
{
var measurement = new TestMeasurement
{
Id = _idCounter++,
Name = $"Measurement-{_idCounter}",
TotalWeight = 100.5 + _idCounter,
- CreatedAt = DateTime.UtcNow
+ CreatedAt = DateTime.UtcNow,
+ Tag = sharedTag,
+ Operator = sharedOperator
};
for (int i = 0; i < pointCount; i++)
{
- var point = CreateMeasurementPoint();
+ var point = CreateMeasurementPoint(sharedTag, sharedOperator);
point.ParentMeasurement = measurement;
measurement.Points.Add(point);
}
@@ -231,7 +279,9 @@ public static class TestDataFactory
///
/// Create a measurement point
///
- public static TestMeasurementPoint CreateMeasurementPoint()
+ public static TestMeasurementPoint CreateMeasurementPoint(
+ SharedTag? sharedTag = null,
+ SharedUser? sharedVerifier = null)
{
var id = _idCounter++;
return new TestMeasurementPoint
@@ -239,7 +289,9 @@ public static class TestDataFactory
Id = id,
Label = $"Point-{id}",
Value = 10.5 + (id * 0.1),
- MeasuredAt = DateTime.UtcNow
+ MeasuredAt = DateTime.UtcNow,
+ Tag = sharedTag,
+ Verifier = sharedVerifier
};
}
diff --git a/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.cs b/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.cs
index bd7768c..44fb88b 100644
--- a/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.cs
+++ b/AyCode.Core/Serializers/Binaries/AcBinaryDeserializer.cs
@@ -934,9 +934,9 @@ public static partial class AcBinaryDeserializer
}
else
{
- // Non-IId: [ObjectRef][hashcode] - lookup by hashcode
+ // Non-IId: [ObjectRef][hashcode] - lookup by hashcode (always Int32)
var hashcode = context.ReadVarInt();
- if (context.ContextClass.TryGetValue(wrapper, hashcode, out var instance))
+ if (wrapper.TryGetValueInt32(hashcode, out var instance))
return instance;
throw new AcBinaryDeserializationException(
@@ -949,7 +949,7 @@ public static partial class AcBinaryDeserializer
private static object? ReadObjectRefInt32(ref BinaryDeserializationContext context, ref TypeMetadataWrapper wrapper)
{
var id = context.ReadVarInt();
- if (context.ContextClass.TryGetValue(wrapper, id, out var instance))
+ if (wrapper.TryGetValueInt32(id, out var instance))
return instance;
throw new AcBinaryDeserializationException(
@@ -961,7 +961,7 @@ public static partial class AcBinaryDeserializer
private static object? ReadObjectRefInt64(ref BinaryDeserializationContext context, ref TypeMetadataWrapper wrapper)
{
var id = context.ReadVarLong();
- if (context.ContextClass.TryGetValue(wrapper, id, out var instance))
+ if (wrapper.TryGetValueInt64(id, out var instance))
return instance;
throw new AcBinaryDeserializationException(
@@ -973,7 +973,7 @@ public static partial class AcBinaryDeserializer
private static object? ReadObjectRefGuid(ref BinaryDeserializationContext context, ref TypeMetadataWrapper wrapper)
{
var id = context.ReadGuidUnsafe();
- if (context.ContextClass.TryGetValue(wrapper, id, out var instance))
+ if (wrapper.TryGetValueGuid(id, out var instance))
return instance;
throw new AcBinaryDeserializationException(
@@ -1012,22 +1012,8 @@ public static partial class AcBinaryDeserializer
PopulateObject(ref context, instance, metadata, depth, skipDefaultWrite: true);
- // Register by Id after populate (Id is now set)
- switch (metadata.IdAccessorType)
- {
- case AcSerializerCommon.IdAccessorType.Int32:
- var intId = metadata.GetIdInt32(instance);
- context.ContextClass.TryGetOrStoreInt32(wrapper, instance, intId);
- break;
- case AcSerializerCommon.IdAccessorType.Int64:
- var longId = metadata.GetIdInt64(instance);
- context.ContextClass.TryGetOrStoreLong(wrapper, instance, longId);
- break;
- case AcSerializerCommon.IdAccessorType.Guid:
- var guidId = metadata.GetIdGuid(instance);
- context.ContextClass.TryGetOrStoreGuid(wrapper, instance, guidId);
- break;
- }
+ // Register by Id after populate - uses typed methods on wrapper
+ RegisterIIdInstance(context.ContextClass, wrapper, instance, metadata);
}
else
{
@@ -1035,13 +1021,13 @@ public static partial class AcBinaryDeserializer
var hashcode = context.ReadVarInt();
// TryGetValue - if already exists, return (shouldn't happen for Object, only ObjectRef)
- if (context.ContextClass.TryGetValue(wrapper, hashcode, out instance))
+ if (wrapper.TryGetValueInt32(hashcode, out instance))
return instance;
- // Create + Register by hashcode
+ // Create + Register by hashcode (always Int32 for Non-IId)
instance = CreateInstance(targetType, metadata);
if (instance == null) return null;
- context.ContextClass.TryGetOrStoreInt32(wrapper, instance, hashcode);
+ wrapper.TryGetOrStoreInt32(hashcode, instance);
// Populate
PopulateObject(ref context, instance, metadata, depth, skipDefaultWrite: true);
@@ -1060,23 +1046,7 @@ public static partial class AcBinaryDeserializer
// Note: For ChainMode, we need IdGetter OR typed getters (IdAccessorType != None)
if (context.IsChainMode && metadata.IsIId && metadata.IdType != null)
{
- object? id;
- switch (metadata.IdAccessorType)
- {
- case AcSerializerCommon.IdAccessorType.Int32:
- id = metadata.GetIdInt32(instance);
- break;
- case AcSerializerCommon.IdAccessorType.Int64:
- id = metadata.GetIdInt64(instance);
- break;
- case AcSerializerCommon.IdAccessorType.Guid:
- id = metadata.GetIdGuid(instance);
- break;
- default:
- id = null;
- break;
- }
-
+ var id = GetIdBoxed(instance, metadata);
if (id != null && !IsDefaultValue(id, metadata.IdType))
{
// Check if we already have this object
@@ -1491,6 +1461,39 @@ public static partial class AcBinaryDeserializer
#endregion
+ #region IId Registration Helpers
+
+ ///
+ /// Registers an IId instance after populate - uses pre-bound delegate, NO SWITCH!
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void RegisterIIdInstance(
+ BinaryDeserializationContextClass contextClass,
+ TypeMetadataWrapper wrapper,
+ object instance,
+ BinaryDeserializeTypeMetadata metadata)
+ {
+ // Pre-bound delegate - no switch needed!
+ wrapper.RegisterById!(instance);
+ }
+
+ ///
+ /// Gets Id as boxed object - only used for ChainMode (rare path).
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static object? GetIdBoxed(object instance, BinaryDeserializeTypeMetadata metadata)
+ {
+ return metadata.IdAccessorType switch
+ {
+ AcSerializerCommon.IdAccessorType.Int32 => metadata.GetIdInt32(instance),
+ AcSerializerCommon.IdAccessorType.Int64 => metadata.GetIdInt64(instance),
+ AcSerializerCommon.IdAccessorType.Guid => metadata.GetIdGuid(instance),
+ _ => null
+ };
+ }
+
+ #endregion
+
#region Type Metadata
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/AyCode.Core/Serializers/SerializationContextBase.cs b/AyCode.Core/Serializers/SerializationContextBase.cs
index 21d08a5..e57eafc 100644
--- a/AyCode.Core/Serializers/SerializationContextBase.cs
+++ b/AyCode.Core/Serializers/SerializationContextBase.cs
@@ -40,8 +40,8 @@ public abstract class SerializationContextBase : AcSerializ
{
Debug.Assert(wrapper.Metadata.IdAccessorType == AcSerializerCommon.IdAccessorType.Int32);
- var getter = (Func