Skip to content

Commit 3c7c7d5

Browse files
committed
Performance improvements to validation/messenger generated code
1 parent cd830ef commit 3c7c7d5

File tree

2 files changed

+49
-49
lines changed

2 files changed

+49
-49
lines changed

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

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ public void Execute(GeneratorExecutionContext context)
6969
// over the created delegate to be able to cache it as an Action<object> instance. This pattern enables the same
7070
// functionality and with almost identical performance (not noticeable in this context anyway), but while preserving
7171
// full runtime type safety (as a safe cast is used to validate the input argument), and with less reflection needed.
72+
// Note that we're deliberately creating a new delegate instance here and not using code that could see the C# compiler
73+
// create a static class to cache a reusable delegate, because each generated method will only be called at most once,
74+
// as the returned delegate will be cached by the MVVM Toolkit itself. So this ensures the the produced code is minimal,
75+
// and that there will be no unnecessary static fields and objects being created and possibly never collected.
7276
// This code takes a class symbol and produces a compilation unit as follows:
7377
//
7478
// // Licensed to the .NET Foundation under one or more agreements.
@@ -90,12 +94,13 @@ public void Execute(GeneratorExecutionContext context)
9094
// [global::System.Obsolete("This method is not intended to be called directly by user code")]
9195
// public static global::System.Action<object> CreateAllPropertiesValidator(<INSTANCE_TYPE> _)
9296
// {
93-
// static void ValidateAllProperties(<INSTANCE_TYPE> instance)
97+
// static void ValidateAllProperties(object obj)
9498
// {
99+
// var instance = (<INSTANCE_TYPE>)obj;
95100
// <BODY>
96101
// }
97102
//
98-
// return static o => ValidateAllProperties((<INSTANCE_TYPE>)o);
103+
// return ValidateAllProperties;
99104
// }
100105
// }
101106
// }
@@ -130,17 +135,18 @@ public void Execute(GeneratorExecutionContext context)
130135
Identifier("ValidateAllProperties"))
131136
.AddModifiers(Token(SyntaxKind.StaticKeyword))
132137
.AddParameterListParameters(
133-
Parameter(Identifier("instance")).WithType(IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))))
134-
.WithBody(Block(EnumerateValidationStatements(classSymbol, validationSymbol).ToArray())),
135-
ReturnStatement(
136-
SimpleLambdaExpression(Parameter(Identifier("o")))
137-
.AddModifiers(Token(SyntaxKind.StaticKeyword))
138-
.WithExpressionBody(
139-
InvocationExpression(IdentifierName("ValidateAllProperties"))
140-
.AddArgumentListArguments(Argument(
141-
CastExpression(
142-
IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)),
143-
IdentifierName("o")))))))))))
138+
Parameter(Identifier("obj")).WithType(PredefinedType(Token(SyntaxKind.ObjectKeyword))))
139+
.WithBody(Block(
140+
LocalDeclarationStatement(
141+
VariableDeclaration(IdentifierName("var")) // Cannot Token(SyntaxKind.VarKeyword) here (throws an ArgumentException)
142+
.AddVariables(
143+
VariableDeclarator(Identifier("instance"))
144+
.WithInitializer(EqualsValueClause(
145+
CastExpression(
146+
IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)),
147+
IdentifierName("obj")))))))
148+
.AddStatements(EnumerateValidationStatements(classSymbol, validationSymbol).ToArray())),
149+
ReturnStatement(IdentifierName("ValidateAllProperties")))))))
144150
.NormalizeWhitespace()
145151
.ToFullString();
146152

Microsoft.Toolkit.Mvvm.SourceGenerators/Messaging/IMessengerRegisterAllGenerator.cs

Lines changed: 30 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -91,25 +91,27 @@ public void Execute(GeneratorExecutionContext context)
9191
// [global::System.Obsolete("This method is not intended to be called directly by user code")]
9292
// public static global::System.Action<IMessenger, object> CreateAllMessagesRegistrator(<RECIPIENT_TYPE> _)
9393
// {
94-
// static void RegisterAll(IMessenger messenger, <INSTANCE_TYPE> instance)
94+
// static void RegisterAll(IMessenger messenger, object obj)
9595
// {
96+
// var recipient = (<INSTANCE_TYPE>)obj;
9697
// <BODY>
9798
// }
9899
//
99-
// return static (m, r) => RegisterAll(m, (<INSTANCE_TYPE>)r);
100+
// return RegisterAll;
100101
// }
101102
//
102103
// [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
103104
// [global::System.Obsolete("This method is not intended to be called directly by user code")]
104105
// public static global::System.Action<IMessenger, object, TToken> CreateAllMessagesRegistratorWithToken<TToken>(<RECIPIENT_TYPE> _)
105106
// where TToken : global::System.IEquatable<TToken>
106107
// {
107-
// static void RegisterAll(IMessenger messenger, <INSTANCE_TYPE> instance, TToken token)
108+
// static void RegisterAll(IMessenger messenger, object obj, TToken token)
108109
// {
110+
// var recipient = (<INSTANCE_TYPE>)obj;
109111
// <BODY>
110112
// }
111113
//
112-
// return static (m, r, t) => RegisterAll(m, (<INSTANCE_TYPE>)r, t);
114+
// return RegisterAll;
113115
// }
114116
// }
115117
// }
@@ -147,21 +149,18 @@ public void Execute(GeneratorExecutionContext context)
147149
.AddModifiers(Token(SyntaxKind.StaticKeyword))
148150
.AddParameterListParameters(
149151
Parameter(Identifier("messenger")).WithType(IdentifierName("IMessenger")),
150-
Parameter(Identifier("recipient")).WithType(IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))))
151-
.WithBody(Block(EnumerateRegistrationStatements(classSymbol, iRecipientSymbol).ToArray())),
152-
ReturnStatement(
153-
ParenthesizedLambdaExpression()
154-
.AddModifiers(Token(SyntaxKind.StaticKeyword))
155-
.AddParameterListParameters(
156-
Parameter(Identifier("m")),
157-
Parameter(Identifier("r")))
158-
.WithExpressionBody(
159-
InvocationExpression(IdentifierName("RegisterAll"))
160-
.AddArgumentListArguments(
161-
Argument(IdentifierName("m")),
162-
Argument(CastExpression(
163-
IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)),
164-
IdentifierName("r")))))))),
152+
Parameter(Identifier("obj")).WithType(PredefinedType(Token(SyntaxKind.ObjectKeyword))))
153+
.WithBody(Block(
154+
LocalDeclarationStatement(
155+
VariableDeclaration(IdentifierName("var"))
156+
.AddVariables(
157+
VariableDeclarator(Identifier("recipient"))
158+
.WithInitializer(EqualsValueClause(
159+
CastExpression(
160+
IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)),
161+
IdentifierName("obj")))))))
162+
.AddStatements(EnumerateRegistrationStatements(classSymbol, iRecipientSymbol).ToArray())),
163+
ReturnStatement(IdentifierName("RegisterAll")))),
165164
MethodDeclaration(
166165
GenericName("global::System.Action").AddTypeArgumentListArguments(
167166
IdentifierName("IMessenger"),
@@ -190,24 +189,19 @@ public void Execute(GeneratorExecutionContext context)
190189
.AddModifiers(Token(SyntaxKind.StaticKeyword))
191190
.AddParameterListParameters(
192191
Parameter(Identifier("messenger")).WithType(IdentifierName("IMessenger")),
193-
Parameter(Identifier("recipient")).WithType(IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))),
192+
Parameter(Identifier("obj")).WithType(PredefinedType(Token(SyntaxKind.ObjectKeyword))),
194193
Parameter(Identifier("token")).WithType(IdentifierName("TToken")))
195-
.WithBody(Block(EnumerateRegistrationStatementsWithTokens(classSymbol, iRecipientSymbol).ToArray())),
196-
ReturnStatement(
197-
ParenthesizedLambdaExpression()
198-
.AddModifiers(Token(SyntaxKind.StaticKeyword))
199-
.AddParameterListParameters(
200-
Parameter(Identifier("m")),
201-
Parameter(Identifier("r")),
202-
Parameter(Identifier("t")))
203-
.WithExpressionBody(
204-
InvocationExpression(IdentifierName("RegisterAll"))
205-
.AddArgumentListArguments(
206-
Argument(IdentifierName("m")),
207-
Argument(CastExpression(
208-
IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)),
209-
IdentifierName("r"))),
210-
Argument(IdentifierName("t"))))))))))
194+
.WithBody(Block(
195+
LocalDeclarationStatement(
196+
VariableDeclaration(IdentifierName("var"))
197+
.AddVariables(
198+
VariableDeclarator(Identifier("recipient"))
199+
.WithInitializer(EqualsValueClause(
200+
CastExpression(
201+
IdentifierName(classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)),
202+
IdentifierName("obj")))))))
203+
.AddStatements(EnumerateRegistrationStatementsWithTokens(classSymbol, iRecipientSymbol).ToArray())),
204+
ReturnStatement(IdentifierName("RegisterAll")))))))
211205
.NormalizeWhitespace()
212206
.ToFullString();
213207

0 commit comments

Comments
 (0)