@@ -28,10 +28,13 @@ public class NeoBinarySerializer
2828 private readonly ConcurrentDictionary < Type , string > _typeNameCache = new ( ) ;
2929 private readonly ConcurrentDictionary < string , Type > _resolvedTypeCache = new ( ) ;
3030 private readonly ConcurrentDictionary < FieldInfo , Func < object , object > > _getterCache = new ( ) ;
31-
31+
3232 // Performance optimization: compiled field setter delegates
3333 private readonly ConcurrentDictionary < FieldInfo , Action < object , object > > _setterCache = new ( ) ;
34-
34+
35+ // Performance optimization: precompiled serializers for complex types
36+ private readonly ConcurrentDictionary < Type , Action < object , BinaryWriter , HashSet < object > , Dictionary < object , int > > > _compiledSerializers = new ( ) ;
37+
3538 // String pooling for frequently used strings
3639 private readonly ConcurrentDictionary < string , string > _stringPool = new ( ) ;
3740
@@ -924,25 +927,53 @@ private void SerializeComplexObject(object obj, BinaryWriter writer, HashSet<obj
924927 Dictionary < object , int > objectMap )
925928 {
926929 var type = obj . GetType ( ) ;
930+
931+ if ( _compiledSerializers . TryGetValue ( type , out var compiledSerializer ) )
932+ {
933+ compiledSerializer ( obj , writer , serializedObjects , objectMap ) ;
934+ }
935+ else
936+ {
937+ var serializer = CreateCompiledSerializer ( type ) ;
938+ _compiledSerializers [ type ] = serializer ;
939+ serializer ( obj , writer , serializedObjects , objectMap ) ;
940+ }
941+ }
942+
943+ private Action < object , BinaryWriter , HashSet < object > , Dictionary < object , int > > CreateCompiledSerializer ( Type type )
944+ {
927945 var fields = GetAllFieldsInHierarchy ( type ) ;
928946
929- writer . Write ( fields . Count ) ;
947+ var objParam = Expression . Parameter ( typeof ( object ) , "obj" ) ;
948+ var writerParam = Expression . Parameter ( typeof ( BinaryWriter ) , "writer" ) ;
949+ var serializedObjectsParam = Expression . Parameter ( typeof ( HashSet < object > ) , "serializedObjects" ) ;
950+ var objectMapParam = Expression . Parameter ( typeof ( Dictionary < object , int > ) , "objectMap" ) ;
951+
952+ var thisParam = Expression . Constant ( this ) ;
953+
954+ var statements = new List < Expression > ( ) ;
955+
956+ // Write field count
957+ statements . Add ( Expression . Call ( writerParam , typeof ( BinaryWriter ) . GetMethod ( "Write" , new [ ] { typeof ( int ) } ) ! , Expression . Constant ( fields . Count ) ) ) ;
930958
931959 foreach ( var field in fields )
932960 {
961+ // Write field name
933962 var fieldName = _stringPool . GetOrAdd ( field . Name , n => n ) ;
934- writer . Write ( fieldName ) ;
935- var getter = _getterCache . GetOrAdd ( field , f =>
936- {
937- var objParam = Expression . Parameter ( typeof ( object ) , "obj" ) ;
938- var castObj = Expression . Convert ( objParam , f . DeclaringType ) ;
939- var fieldExpr = Expression . Field ( castObj , f ) ;
940- var convertExpr = Expression . Convert ( fieldExpr , typeof ( object ) ) ;
941- return Expression . Lambda < Func < object , object > > ( convertExpr , objParam ) . Compile ( ) ;
942- } ) ;
943- var value = getter ( obj ) ;
944- SerializeObject ( value , writer , serializedObjects , objectMap ) ;
963+ statements . Add ( Expression . Call ( writerParam , typeof ( BinaryWriter ) . GetMethod ( "Write" , new [ ] { typeof ( string ) } ) ! , Expression . Constant ( fieldName ) ) ) ;
964+
965+ // Get field value
966+ var castObj = Expression . Convert ( objParam , field . DeclaringType ! ) ;
967+ var fieldExpr = Expression . Field ( castObj , field ) ;
968+ var valueExpr = Expression . Convert ( fieldExpr , typeof ( object ) ) ;
969+
970+ // Call SerializeObject
971+ statements . Add ( Expression . Call ( thisParam , typeof ( NeoBinarySerializer ) . GetMethod ( "SerializeObject" , BindingFlags . NonPublic | BindingFlags . Instance ) ! , valueExpr , writerParam , serializedObjectsParam , objectMapParam ) ) ;
945972 }
973+
974+ var block = Expression . Block ( statements ) ;
975+ var lambda = Expression . Lambda < Action < object , BinaryWriter , HashSet < object > , Dictionary < object , int > > > ( block , objParam , writerParam , serializedObjectsParam , objectMapParam ) ;
976+ return lambda . Compile ( ) ;
946977 }
947978
948979 private object DeserializeComplexObject ( Type type , BinaryReader reader ,
@@ -972,45 +1003,54 @@ private object DeserializeComplexObject(Type type, BinaryReader reader,
9721003 {
9731004 continue ;
9741005 }
975-
1006+
9761007 // Use reflection to set the field value on the boxed struct
9771008 field . SetValue ( obj , value ) ;
9781009 }
9791010 }
980-
1011+
9811012 return obj ;
9821013 }
9831014 else
9841015 {
985- // Regular reference type handling
1016+ // Regular reference type handling with optimized field lookup
1017+ var fields = _fieldCache . GetOrAdd ( type , t => GetAllFieldsInHierarchy ( t ) . ToArray ( ) ) ;
1018+ var fieldIndex = 0 ;
1019+
9861020 for ( int i = 0 ; i < fieldCount ; i ++ )
9871021 {
9881022 var fieldName = reader . ReadString ( ) ;
9891023 var value = DeserializeObject ( reader , deserializedObjects ) ;
9901024
991- var field = GetFieldInHierarchy ( type , fieldName ) ;
992- if ( field != null )
1025+ // Find the field by name from cached fields
1026+ FieldInfo ? field = null ;
1027+ while ( fieldIndex < fields . Length && ( field = fields [ fieldIndex ] ) . Name != fieldName )
1028+ {
1029+ fieldIndex ++ ;
1030+ }
1031+
1032+ if ( field != null && field . Name == fieldName )
9931033 {
9941034 // Use cached setter for better performance, but fallback to reflection for read-only fields
9951035 if ( field . IsInitOnly || field . IsLiteral )
9961036 {
9971037 // Skip read-only fields (they should be handled by constructor)
9981038 continue ;
9991039 }
1000-
1040+
10011041 var setter = _setterCache . GetOrAdd ( field , f =>
10021042 {
10031043 var objParam = Expression . Parameter ( typeof ( object ) , "obj" ) ;
10041044 var valueParam = Expression . Parameter ( typeof ( object ) , "value" ) ;
1005-
1045+
10061046 var castObj = Expression . Convert ( objParam , type ) ;
10071047 var castValue = Expression . Convert ( valueParam , f . FieldType ) ;
10081048 var fieldAccess = Expression . Field ( castObj , f ) ;
10091049 var assign = Expression . Assign ( fieldAccess , castValue ) ;
1010-
1050+
10111051 return Expression . Lambda < Action < object , object > > ( assign , objParam , valueParam ) . Compile ( ) ;
10121052 } ) ;
1013-
1053+
10141054 setter ( obj , value ) ;
10151055 }
10161056 }
0 commit comments