@@ -834,9 +834,6 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
834834 {
835835 using ImmutableArrayBuilder < StatementSyntax > setterStatements = ImmutableArrayBuilder < StatementSyntax > . Rent ( ) ;
836836
837- // Get the property type syntax
838- TypeSyntax propertyType = IdentifierName ( propertyInfo . TypeNameWithNullabilityAnnotations ) ;
839-
840837 string getterFieldIdentifierName ;
841838 ExpressionSyntax getterFieldExpression ;
842839 ExpressionSyntax setterFieldExpression ;
@@ -872,7 +869,7 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
872869 // <PROPERTY_TYPE> __oldValue = <FIELD_EXPRESSIONS>;
873870 setterStatements . Add (
874871 LocalDeclarationStatement (
875- VariableDeclaration ( propertyType )
872+ VariableDeclaration ( GetMaybeNullPropertyType ( propertyInfo ) )
876873 . AddVariables (
877874 VariableDeclarator ( Identifier ( "__oldValue" ) )
878875 . WithInitializer ( EqualsValueClause ( setterFieldExpression ) ) ) ) ) ;
@@ -1001,6 +998,9 @@ public static MemberDeclarationSyntax GetPropertySyntax(PropertyInfo propertyInf
1001998 Argument ( LiteralExpression ( SyntaxKind . StringLiteralExpression , Literal ( propertyInfo . PropertyName ) ) ) ) ) ) ;
1002999 }
10031000
1001+ // Get the property type syntax
1002+ TypeSyntax propertyType = IdentifierName ( propertyInfo . TypeNameWithNullabilityAnnotations ) ;
1003+
10041004 // Generate the inner setter block as follows:
10051005 //
10061006 // if (!global::System.Collections.Generic.EqualityComparer<<PROPERTY_TYPE>>.Default.Equals(<FIELD_EXPRESSION>, value))
@@ -1128,17 +1128,8 @@ public static ImmutableArray<MemberDeclarationSyntax> GetOnPropertyChangeMethods
11281128 Comment ( $ "/// <remarks>This method is invoked right before the value of <see cref=\" { propertyInfo . PropertyName } \" /> is changed.</remarks>") ) , SyntaxKind . OpenBracketToken , TriviaList ( ) ) ) )
11291129 . WithSemicolonToken ( Token ( SyntaxKind . SemicolonToken ) ) ;
11301130
1131- // Prepare the nullable type for the previous property value. This is needed because if the type is a reference
1132- // type, the previous value might be null even if the property type is not nullable, as the first invocation would
1133- // happen when the property is first set to some value that is not null (but the backing field would still be so).
1134- // As a cheap way to check whether we need to add nullable, we can simply check whether the type name with nullability
1135- // annotations ends with a '?'. If it doesn't and the type is a reference type, we add it. Otherwise, we keep it.
1136- TypeSyntax oldValueTypeSyntax = propertyInfo . IsReferenceTypeOrUnconstraindTypeParameter switch
1137- {
1138- true when ! propertyInfo . TypeNameWithNullabilityAnnotations . EndsWith ( "?" )
1139- => IdentifierName ( $ "{ propertyInfo . TypeNameWithNullabilityAnnotations } ?") ,
1140- _ => parameterType
1141- } ;
1131+ // Get the type for the 'oldValue' parameter (which can be null on first invocation)
1132+ TypeSyntax oldValueTypeSyntax = GetMaybeNullPropertyType ( propertyInfo ) ;
11421133
11431134 // Construct the generated method as follows:
11441135 //
@@ -1224,6 +1215,26 @@ public static ImmutableArray<MemberDeclarationSyntax> GetOnPropertyChangeMethods
12241215 onPropertyChanged2Declaration ) ;
12251216 }
12261217
1218+ /// <summary>
1219+ /// Gets the <see cref="TypeSyntax"/> for the type of a given property, when it can possibly be <see langword="null"/>.
1220+ /// </summary>
1221+ /// <param name="propertyInfo">The input <see cref="PropertyInfo"/> instance to process.</param>
1222+ /// <returns>The type of a given property, when it can possibly be <see langword="null"/></returns>
1223+ private static TypeSyntax GetMaybeNullPropertyType ( PropertyInfo propertyInfo )
1224+ {
1225+ // Prepare the nullable type for the previous property value. This is needed because if the type is a reference
1226+ // type, the previous value might be null even if the property type is not nullable, as the first invocation would
1227+ // happen when the property is first set to some value that is not null (but the backing field would still be so).
1228+ // As a cheap way to check whether we need to add nullable, we can simply check whether the type name with nullability
1229+ // annotations ends with a '?'. If it doesn't and the type is a reference type, we add it. Otherwise, we keep it.
1230+ return propertyInfo . IsReferenceTypeOrUnconstraindTypeParameter switch
1231+ {
1232+ true when ! propertyInfo . TypeNameWithNullabilityAnnotations . EndsWith ( "?" )
1233+ => IdentifierName ( $ "{ propertyInfo . TypeNameWithNullabilityAnnotations } ?") ,
1234+ _ => IdentifierName ( propertyInfo . TypeNameWithNullabilityAnnotations )
1235+ } ;
1236+ }
1237+
12271238 /// <summary>
12281239 /// Gets a <see cref="CompilationUnitSyntax"/> instance with the cached args of a specified type.
12291240 /// </summary>
0 commit comments