Skip to content

Commit 27f429f

Browse files
committed
Improved [ObservableProperty] codegen for ObservableObject
1 parent 2e8149f commit 27f429f

File tree

1 file changed

+39
-2
lines changed

1 file changed

+39
-2
lines changed

Microsoft.Toolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.cs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,11 @@ private static void OnExecute(
8080

8181
// Check whether the current type implements INotifyPropertyChanging and whether it inherits from ObservableValidator
8282
bool
83+
isObservableObject = classDeclarationSymbol.InheritsFrom(observableObjectSymbol),
8384
isObservableValidator = classDeclarationSymbol.InheritsFrom(observableValidatorSymbol),
8485
isNotifyPropertyChanging =
86+
isObservableObject ||
8587
classDeclarationSymbol.AllInterfaces.Contains(iNotifyPropertyChangingSymbol, SymbolEqualityComparer.Default) ||
86-
classDeclarationSymbol.InheritsFrom(observableObjectSymbol) ||
8788
classDeclarationSymbol.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, observableObjectAttributeSymbol));
8889

8990
// Create the class declaration for the user type. This will produce a tree as follows:
@@ -95,7 +96,14 @@ private static void OnExecute(
9596
var classDeclarationSyntax =
9697
ClassDeclaration(classDeclarationSymbol.Name)
9798
.WithModifiers(classDeclaration.Modifiers)
98-
.AddMembers(items.Select(item => CreatePropertyDeclaration(context, item.LeadingTrivia, item.FieldSymbol, isNotifyPropertyChanging, isObservableValidator)).ToArray());
99+
.AddMembers(items.Select(item =>
100+
CreatePropertyDeclaration(
101+
context,
102+
item.LeadingTrivia,
103+
item.FieldSymbol,
104+
isNotifyPropertyChanging,
105+
isObservableObject,
106+
isObservableValidator)).ToArray());
99107

100108
TypeDeclarationSyntax typeDeclarationSyntax = classDeclarationSyntax;
101109

@@ -137,6 +145,7 @@ private static void OnExecute(
137145
/// <param name="leadingTrivia">The leading trivia for the field to process.</param>
138146
/// <param name="fieldSymbol">The input <see cref="IFieldSymbol"/> instance to process.</param>
139147
/// <param name="isNotifyPropertyChanging">Indicates whether or not <see cref="INotifyPropertyChanging"/> is also implemented.</param>
148+
/// <param name="isObservableObject">Indicates whether or not the containing type inherits from <c>ObservableObject</c>.</param>
140149
/// <param name="isObservableValidator">Indicates whether or not the containing type inherits from <c>ObservableValidator</c>.</param>
141150
/// <returns>A generated <see cref="PropertyDeclarationSyntax"/> instance for the input field.</returns>
142151
[Pure]
@@ -145,6 +154,7 @@ private static PropertyDeclarationSyntax CreatePropertyDeclaration(
145154
SyntaxTriviaList leadingTrivia,
146155
IFieldSymbol fieldSymbol,
147156
bool isNotifyPropertyChanging,
157+
bool isObservableObject,
148158
bool isObservableValidator)
149159
{
150160
// Get the field type and the target property name
@@ -246,6 +256,33 @@ private static PropertyDeclarationSyntax CreatePropertyDeclaration(
246256
_ => Block(IfStatement(setPropertyExpression, Block(dependentPropertyNotificationStatements)))
247257
};
248258
}
259+
else if (isObservableObject)
260+
{
261+
// Generate the inner setter block as follows:
262+
//
263+
// SetProperty(ref <FIELD_NAME>, value);
264+
//
265+
// Or in case there is at least one dependent property:
266+
//
267+
// if (SetProperty(ref <FIELD_NAME>, value))
268+
// {
269+
// OnPropertyChanged("Property1"); // Optional
270+
// OnPropertyChanged("Property2");
271+
// ...
272+
// OnPropertyChanged("PropertyN");
273+
// }
274+
InvocationExpressionSyntax setPropertyExpression =
275+
InvocationExpression(IdentifierName("SetProperty"))
276+
.AddArgumentListArguments(
277+
Argument(IdentifierName(fieldSymbol.Name)).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),
278+
Argument(IdentifierName("value")));
279+
280+
setterBlock = dependentPropertyNotificationStatements.Count switch
281+
{
282+
0 => Block(ExpressionStatement(setPropertyExpression)),
283+
_ => Block(IfStatement(setPropertyExpression, Block(dependentPropertyNotificationStatements)))
284+
};
285+
}
249286
else
250287
{
251288
BlockSyntax updateAndNotificationBlock = Block();

0 commit comments

Comments
 (0)