Skip to content

Commit 5abba05

Browse files
committed
Enabled property args caching for ObservableValidator properties
1 parent 94f8baf commit 5abba05

File tree

1 file changed

+65
-29
lines changed

1 file changed

+65
-29
lines changed

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

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ private static PropertyDeclarationSyntax CreatePropertyDeclaration(
206206
InvocationExpression(IdentifierName("OnPropertyChanged"))
207207
.AddArgumentListArguments(Argument(MemberAccessExpression(
208208
SyntaxKind.SimpleMemberAccessExpression,
209-
AliasQualifiedName(IdentifierName(Token(SyntaxKind.GlobalKeyword)), IdentifierName("Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs")),
209+
IdentifierName("global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs"),
210210
IdentifierName($"{dependentPropertyName}{nameof(PropertyChangedEventArgs)}"))))));
211211
}
212212
else if (attributeArgument.Kind == TypedConstantKind.Array)
@@ -227,7 +227,7 @@ private static PropertyDeclarationSyntax CreatePropertyDeclaration(
227227
InvocationExpression(IdentifierName("OnPropertyChanged"))
228228
.AddArgumentListArguments(Argument(MemberAccessExpression(
229229
SyntaxKind.SimpleMemberAccessExpression,
230-
AliasQualifiedName(IdentifierName(Token(SyntaxKind.GlobalKeyword)), IdentifierName("Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs")),
230+
IdentifierName("global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs"),
231231
IdentifierName($"{currentPropertyName}{nameof(PropertyChangedEventArgs)}"))))));
232232
}
233233
}
@@ -257,32 +257,68 @@ private static PropertyDeclarationSyntax CreatePropertyDeclaration(
257257

258258
setterBlock = Block();
259259
}
260-
261-
// Generate the inner setter block as follows:
262-
//
263-
// SetProperty(ref <FIELD_NAME>, value, true);
264-
//
265-
// Or in case there is at least one dependent property:
266-
//
267-
// if (SetProperty(ref <FIELD_NAME>, value, true))
268-
// {
269-
// OnPropertyChanged(global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs.Property1PropertyChangedEventArgs); // Optional
270-
// OnPropertyChanged(global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs.Property2PropertyChangedEventArgs);
271-
// ...
272-
// OnPropertyChanged(global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs.PropertyNPropertyChangedEventArgs);
273-
// }
274-
InvocationExpressionSyntax setPropertyExpression =
275-
InvocationExpression(IdentifierName("SetProperty"))
276-
.AddArgumentListArguments(
277-
Argument(IdentifierName(fieldSymbol.Name)).WithRefOrOutKeyword(Token(SyntaxKind.RefKeyword)),
278-
Argument(IdentifierName("value")),
279-
Argument(LiteralExpression(SyntaxKind.TrueLiteralExpression)));
280-
281-
setterBlock = dependentPropertyNotificationStatements.Count switch
260+
else
282261
{
283-
0 => Block(ExpressionStatement(setPropertyExpression)),
284-
_ => Block(IfStatement(setPropertyExpression, Block(dependentPropertyNotificationStatements)))
285-
};
262+
propertyChangedNames.Add(propertyName);
263+
propertyChangingNames.Add(propertyName);
264+
265+
// Generate the inner setter block as follows:
266+
//
267+
// if (!global::System.Collections.Generic.EqualityComparer<<FIELD_TYPE>>.Default.Equals(<FIELD_NAME>, value))
268+
// {
269+
// OnPropertyChanging(global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs.PropertyNamePropertyChangingEventArgs); // Optional
270+
// <FIELD_NAME> = value;
271+
// OnPropertyChanged(global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs.PropertyNamePropertyChangedEventArgs);
272+
// ValidateProperty(value, <PROPERTY_NAME>);
273+
// OnPropertyChanged(global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs.Property1PropertyChangedEventArgs); // Optional
274+
// OnPropertyChanged(global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs.Property2PropertyChangedEventArgs);
275+
// ...
276+
// OnPropertyChanged(global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs.PropertyNPropertyChangedEventArgs);
277+
// }
278+
//
279+
// The reason why the code is explicitly generated instead of just calling ObservableValidator.SetProperty() is so that we can
280+
// take advantage of the cached property changed arguments for the current property as well, not just for the dependent ones.
281+
setterBlock = Block(
282+
IfStatement(
283+
PrefixUnaryExpression(
284+
SyntaxKind.LogicalNotExpression,
285+
InvocationExpression(
286+
MemberAccessExpression(
287+
SyntaxKind.SimpleMemberAccessExpression,
288+
MemberAccessExpression(
289+
SyntaxKind.SimpleMemberAccessExpression,
290+
GenericName(Identifier("global::System.Collections.Generic.EqualityComparer"))
291+
.AddTypeArgumentListArguments(IdentifierName(typeName)),
292+
IdentifierName("Default")),
293+
IdentifierName("Equals")))
294+
.AddArgumentListArguments(
295+
Argument(IdentifierName(fieldSymbol.Name)),
296+
Argument(IdentifierName("value")))),
297+
Block(
298+
ExpressionStatement(
299+
InvocationExpression(IdentifierName("OnPropertyChanging"))
300+
.AddArgumentListArguments(Argument(MemberAccessExpression(
301+
SyntaxKind.SimpleMemberAccessExpression,
302+
IdentifierName("global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs"),
303+
IdentifierName($"{propertyName}{nameof(PropertyChangingEventArgs)}"))))),
304+
ExpressionStatement(
305+
AssignmentExpression(
306+
SyntaxKind.SimpleAssignmentExpression,
307+
IdentifierName(fieldSymbol.Name),
308+
IdentifierName("value"))),
309+
ExpressionStatement(
310+
InvocationExpression(IdentifierName("OnPropertyChanged"))
311+
.AddArgumentListArguments(Argument(MemberAccessExpression(
312+
SyntaxKind.SimpleMemberAccessExpression,
313+
IdentifierName("global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs"),
314+
IdentifierName($"{propertyName}{nameof(PropertyChangedEventArgs)}"))))),
315+
ExpressionStatement(
316+
InvocationExpression(IdentifierName("ValidateProperty"))
317+
.AddArgumentListArguments(
318+
Argument(IdentifierName("value")),
319+
Argument(LiteralExpression(SyntaxKind.StringLiteralExpression, Literal(propertyName))))))
320+
.AddStatements(dependentPropertyNotificationStatements.ToArray())));
321+
}
286322
}
287323
else
288324
{
@@ -297,7 +333,7 @@ private static PropertyDeclarationSyntax CreatePropertyDeclaration(
297333
InvocationExpression(IdentifierName("OnPropertyChanging"))
298334
.AddArgumentListArguments(Argument(MemberAccessExpression(
299335
SyntaxKind.SimpleMemberAccessExpression,
300-
AliasQualifiedName(IdentifierName(Token(SyntaxKind.GlobalKeyword)), IdentifierName("Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs")),
336+
IdentifierName("global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs"),
301337
IdentifierName($"{propertyName}{nameof(PropertyChangingEventArgs)}"))))));
302338
}
303339

@@ -317,7 +353,7 @@ private static PropertyDeclarationSyntax CreatePropertyDeclaration(
317353
InvocationExpression(IdentifierName("OnPropertyChanged"))
318354
.AddArgumentListArguments(Argument(MemberAccessExpression(
319355
SyntaxKind.SimpleMemberAccessExpression,
320-
AliasQualifiedName(IdentifierName(Token(SyntaxKind.GlobalKeyword)), IdentifierName("Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs")),
356+
IdentifierName("global::Microsoft.Toolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedOrChangingArgs"),
321357
IdentifierName($"{propertyName}{nameof(PropertyChangedEventArgs)}"))))));
322358

323359
// Add the dependent property notifications at the end

0 commit comments

Comments
 (0)