@@ -9,13 +9,16 @@ public class AdHocUnionCodeGenerator : CodeGeneratorBase
99
1010 private readonly AdHocUnionSourceGenState _state ;
1111 private readonly StringBuilder _sb ;
12+ private readonly bool _useSharedObjectForRefTypes ;
1213
1314 public AdHocUnionCodeGenerator (
1415 AdHocUnionSourceGenState state ,
1516 StringBuilder sb )
1617 {
1718 _state = state ;
1819 _sb = sb ;
20+ _useSharedObjectForRefTypes = state . Settings . UseSingleBackingField
21+ || _state . MemberTypes . Where ( t => t . IsReferenceType && t . TypeDuplicateCounter <= 1 ) . Select ( t => t . TypeFullyQualified ) . Count ( ) >= 2 ;
1922 }
2023
2124 public override void Generate ( CancellationToken cancellationToken )
@@ -247,7 +250,7 @@ private void GenerateToString()
247250 var memberType = _state . MemberTypes [ i ] ;
248251
249252 _sb . Append ( @"
250- " ) . Append ( i + 1 ) . Append ( " => this. " ) . Append ( memberType . BackingFieldName ) ;
253+ " ) . Append ( i + 1 ) . Append ( " => " ) . AppendBackingFieldAccess ( _state , _useSharedObjectForRefTypes , memberType ) ;
251254
252255 if ( memberType . SpecialType != SpecialType . System_String )
253256 {
@@ -289,7 +292,7 @@ public override int GetHashCode()
289292 _sb . Append ( @"
290293 " ) . Append ( i + 1 ) . Append ( " => " ) ;
291294
292- _sb . Append ( "global::System.HashCode.Combine(" ) . AppendTypeFullyQualified ( _state ) . Append ( "._typeHashCode, this. " ) . Append ( memberType . BackingFieldName ) ;
295+ _sb . Append ( "global::System.HashCode.Combine(" ) . AppendTypeFullyQualified ( _state ) . Append ( "._typeHashCode, " ) . AppendBackingFieldAccess ( _state , _useSharedObjectForRefTypes , memberType ) ;
293296
294297 if ( memberType . IsReferenceType )
295298 _sb . Append ( "?" ) ;
@@ -366,14 +369,22 @@ public bool Equals(").AppendTypeFullyQualifiedNullAnnotated(_state).Append(@" ot
366369 for ( var i = 0 ; i < _state . MemberTypes . Count ; i ++ )
367370 {
368371 var memberType = _state . MemberTypes [ i ] ;
372+ var useSharedObjectBackingField = _state . UseSharedObjectBackingField ( _useSharedObjectForRefTypes , memberType ) ;
369373
370374 _sb . Append ( @"
371375 " ) . Append ( i + 1 ) . Append ( " => " ) ;
372376
373377 if ( memberType . IsReferenceType )
374- _sb . Append ( "this." ) . Append ( memberType . BackingFieldName ) . Append ( " is null ? other." ) . Append ( memberType . BackingFieldName ) . Append ( " is null : " ) ;
378+ {
379+ _sb . Append ( "this." ) . AppendBackingFieldName ( useSharedObjectBackingField , memberType ) . Append ( " is null ? other." ) . AppendBackingFieldName ( _state , _useSharedObjectForRefTypes , memberType ) . Append ( " is null : " ) ;
380+ }
375381
376- _sb . Append ( "this." ) . Append ( memberType . BackingFieldName ) . Append ( ".Equals(other." ) . Append ( memberType . BackingFieldName ) ;
382+ if ( useSharedObjectBackingField )
383+ {
384+ _sb . Append ( "this._valueIndex == other._valueIndex && " ) ;
385+ }
386+
387+ _sb . AppendBackingFieldAccess ( useSharedObjectBackingField , memberType , nullAnnotated : false , suppressed : true ) . Append ( ".Equals(" ) . AppendBackingFieldAccess ( _state , _useSharedObjectForRefTypes , memberType , qualifier : "other" ) ;
377388
378389 if ( memberType . SpecialType == SpecialType . System_String )
379390 _sb . Append ( ", global::System.StringComparison." ) . Append ( Enum . GetName ( typeof ( StringComparison ) , _state . Settings . DefaultStringComparison ) ) ;
@@ -523,7 +534,7 @@ private void GenerateIndexBasedActionSwitchBody(bool withState, bool isPartially
523534 if ( withState )
524535 _sb . AppendEscaped ( _state . Settings . SwitchMapStateParameterName ) . Append ( ", " ) ;
525536
526- _sb . Append ( "this." ) . Append ( memberType . BackingFieldName ) . Append ( memberType . IsReferenceType && memberType . NullableAnnotation != NullableAnnotation . Annotated ? "!" : null ) . Append ( @");
537+ _sb . AppendBackingFieldAccess ( _state , _useSharedObjectForRefTypes , memberType ) . Append ( memberType . IsReferenceType && memberType . NullableAnnotation != NullableAnnotation . Annotated ? "!" : null ) . Append ( @");
527538 return;" ) ;
528539 }
529540
@@ -684,7 +695,7 @@ private void GenerateIndexBasedFuncSwitchBody(bool withState, bool isPartially)
684695 if ( withState )
685696 _sb . AppendEscaped ( _state . Settings . SwitchMapStateParameterName ) . Append ( ", " ) ;
686697
687- _sb . Append ( "this." ) . Append ( memberType . BackingFieldName ) . Append ( memberType is { IsReferenceType : true , Setting . IsNullableReferenceType : false } ? "!" : null ) . Append ( ");" ) ;
698+ _sb . AppendBackingFieldAccess ( _state , _useSharedObjectForRefTypes , memberType ) . Append ( memberType is { IsReferenceType : true , Setting . IsNullableReferenceType : false } ? "!" : null ) . Append ( ");" ) ;
688699 }
689700
690701 _sb . Append ( @"
@@ -866,7 +877,7 @@ private void GenerateConstructors()
866877
867878 _sb . Append ( @")
868879 {
869- this. " ) . Append ( memberType . BackingFieldName ) . Append ( " = " ) . AppendEscaped ( argName ) . Append ( @";
880+ " ) . AppendBackingFieldAccess ( _state , _useSharedObjectForRefTypes , memberType , false ) . Append ( " = " ) . AppendEscaped ( argName ) . Append ( @";
870881 this._valueIndex = " ) ;
871882
872883 if ( hasDuplicates )
@@ -910,15 +921,32 @@ private void GenerateFactoriesForTypeDuplicates()
910921
911922 private void GenerateMemberTypeFieldsAndProps ( )
912923 {
924+ var objBackingFieldWritten = false ;
925+
913926 for ( var i = 0 ; i < _state . MemberTypes . Count ; i ++ )
914927 {
915928 var memberType = _state . MemberTypes [ i ] ;
916929
917930 if ( memberType . TypeDuplicateCounter > 1 )
918931 continue ;
919932
920- _sb . Append ( @"
933+ var useSharedObjectBackingField = _state . UseSharedObjectBackingField ( _useSharedObjectForRefTypes , memberType ) ;
934+
935+ if ( useSharedObjectBackingField )
936+ {
937+ if ( objBackingFieldWritten )
938+ continue ;
939+
940+ objBackingFieldWritten = true ;
941+
942+ _sb . Append ( @"
943+ private readonly object? _obj;" ) ;
944+ }
945+ else
946+ {
947+ _sb . Append ( @"
921948 private readonly " ) . AppendTypeFullyQualifiedNullAnnotated ( memberType ) . Append ( " " ) . Append ( memberType . BackingFieldName ) . Append ( ";" ) ;
949+ }
922950 }
923951
924952 for ( var i = 0 ; i < _state . MemberTypes . Count ; i ++ )
@@ -942,7 +970,7 @@ private void GenerateMemberTypeFieldsAndProps()
942970 /// </summary>
943971 /// <exception cref=""global::System.InvalidOperationException"">If the current value is not of type " ) . AppendTypeForXmlComment ( memberType ) . Append ( @".</exception>
944972 public " ) . AppendTypeFullyQualified ( memberType ) . Append ( " As" ) . Append ( memberType . Name ) . Append ( " => Is" ) . Append ( memberType . Name )
945- . Append ( " ? this. " ) . Append ( memberType . BackingFieldName ) . Append ( memberType . IsReferenceType && memberType . NullableAnnotation != NullableAnnotation . Annotated ? "!" : null )
973+ . Append ( " ? " ) . AppendBackingFieldAccess ( _state , _useSharedObjectForRefTypes , memberType ) . Append ( memberType . IsReferenceType && memberType . NullableAnnotation != NullableAnnotation . Annotated ? "!" : null )
946974 . Append ( " : throw new global::System.InvalidOperationException($\" '{nameof(" ) . AppendTypeFullyQualified ( _state ) . Append ( ")}' is not of type '" ) . AppendTypeMinimallyQualified ( memberType ) . Append ( "'.\" );" ) ;
947975 }
948976 }
@@ -964,7 +992,15 @@ private void GenerateRawValueGetter()
964992 }
965993
966994 _sb . Append ( @"
967- public object" ) . Append ( hasNullableTypes ? "?" : null ) . Append ( @" Value => this._valueIndex switch
995+ public object" ) . Append ( hasNullableTypes ? "?" : null ) . Append ( " Value => " ) ;
996+
997+ if ( _state . Settings . UseSingleBackingField )
998+ {
999+ _sb . Append ( "this._obj!;" ) ;
1000+ return ;
1001+ }
1002+
1003+ _sb . Append ( @"this._valueIndex switch
9681004 {" ) ;
9691005
9701006 if ( ! _state . IsReferenceType )
@@ -978,7 +1014,7 @@ private void GenerateRawValueGetter()
9781014 var memberType = _state . MemberTypes [ i ] ;
9791015
9801016 _sb . Append ( @"
981- " ) . Append ( i + 1 ) . Append ( " => this. " ) . Append ( memberType . BackingFieldName ) . Append ( memberType . IsReferenceType && ! hasNullableTypes ? "!" : null ) . Append ( "," ) ;
1017+ " ) . Append ( i + 1 ) . Append ( " => " ) . AppendBackingFieldAccess ( _state , _useSharedObjectForRefTypes , memberType , withCast : false , nullAnnotated : false , suppressed : false ) . Append ( memberType . IsReferenceType && ! hasNullableTypes ? "!" : null ) . Append ( "," ) ;
9821018 }
9831019
9841020 _sb . Append ( @"
@@ -1004,4 +1040,91 @@ public static StringBuilder AppendMemberTypes(this StringBuilder sb, IReadOnlyLi
10041040
10051041 return sb ;
10061042 }
1043+
1044+ public static bool UseSharedObjectBackingField (
1045+ this AdHocUnionSourceGenState state ,
1046+ bool useSharedObjectForRefTypes ,
1047+ AdHocUnionMemberTypeState memberType )
1048+ {
1049+ return state . Settings . UseSingleBackingField || ( useSharedObjectForRefTypes && memberType . IsReferenceType ) ;
1050+ }
1051+
1052+ public static StringBuilder AppendBackingFieldAccess (
1053+ this StringBuilder sb ,
1054+ AdHocUnionSourceGenState state ,
1055+ bool useSharedObjectForRefTypes ,
1056+ AdHocUnionMemberTypeState memberType ,
1057+ bool withCast = true ,
1058+ bool nullAnnotated = true ,
1059+ bool suppressed = false ,
1060+ string qualifier = "this" )
1061+ {
1062+ var useSharedObjectBackingField = state . UseSharedObjectBackingField ( useSharedObjectForRefTypes , memberType ) ;
1063+
1064+ return AppendBackingFieldAccess ( sb , useSharedObjectBackingField , memberType , withCast , nullAnnotated , suppressed , qualifier ) ;
1065+ }
1066+
1067+ public static StringBuilder AppendBackingFieldAccess (
1068+ this StringBuilder sb ,
1069+ bool useSharedObjectBackingField ,
1070+ AdHocUnionMemberTypeState memberType ,
1071+ bool withCast = true ,
1072+ bool nullAnnotated = true ,
1073+ bool suppressed = false ,
1074+ string qualifier = "this" )
1075+ {
1076+ if ( useSharedObjectBackingField )
1077+ {
1078+ if ( withCast )
1079+ {
1080+ sb . Append ( "((" ) ;
1081+
1082+ if ( nullAnnotated )
1083+ {
1084+ sb . AppendTypeFullyQualifiedNullAnnotated ( memberType ) ;
1085+ }
1086+ else
1087+ {
1088+ sb . AppendTypeFullyQualified ( memberType ) ;
1089+ }
1090+
1091+ sb . Append ( ")" ) ;
1092+ }
1093+
1094+ sb . Append ( qualifier ) . Append ( "._obj" ) ;
1095+
1096+ if ( withCast )
1097+ {
1098+ if ( suppressed || memberType is { IsReferenceType : false , IsNullableStruct : false } )
1099+ sb . Append ( "!" ) ;
1100+
1101+ sb . Append ( ")" ) ;
1102+ }
1103+ }
1104+ else
1105+ {
1106+ sb . Append ( qualifier ) . Append ( "." ) . Append ( memberType . BackingFieldName ) ;
1107+ }
1108+
1109+ return sb ;
1110+ }
1111+
1112+ public static StringBuilder AppendBackingFieldName (
1113+ this StringBuilder sb ,
1114+ AdHocUnionSourceGenState state ,
1115+ bool useSharedObjectForRefTypes ,
1116+ AdHocUnionMemberTypeState memberType )
1117+ {
1118+ var useSharedObjectBackingField = state . UseSharedObjectBackingField ( useSharedObjectForRefTypes , memberType ) ;
1119+
1120+ return AppendBackingFieldName ( sb , useSharedObjectBackingField , memberType ) ;
1121+ }
1122+
1123+ public static StringBuilder AppendBackingFieldName (
1124+ this StringBuilder sb ,
1125+ bool useSharedObjectBackingField ,
1126+ AdHocUnionMemberTypeState memberType )
1127+ {
1128+ return sb . Append ( useSharedObjectBackingField ? "_obj" : memberType . BackingFieldName ) ;
1129+ }
10071130}
0 commit comments