-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Re-introduce runtime code generation #3669
Conversation
9c75068
to
da21d5f
Compare
This will conflict with #3595. Which one should go in first? I assume that @benjaminpetit's is ready to be merged |
public class RuntimeCodeGenTests | ||
{ | ||
[Fact] | ||
public void RuntimeCodeGenAddsSupportClasses() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth adding a functional that starts a silo and verifies the grain and serialization works?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing, will do
Although what you are solving by not requiring a SerializationManager for codegen is what @benjaminpetit wanted to do eventually, but couldn't do yet, so he hacked around it... maybe it's better to merge this one first and have him rebase on this one? I'm fine with whatever you guys decide. Although from what I see about the extension methods discussion this PR might take longer? |
tempPartManager.AddFeatureProvider(new BuiltInTypesSerializationFeaturePopulator()); | ||
|
||
var codeGenerator = new RoslynCodeGenerator(tempPartManager, new NullLoggerFactory()); | ||
var generatedAssembly = codeGenerator.GenerateAndLoadForAssemblies(manager.Assemblies); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it mean that codegen is run immediately? Shouldn't it wait until a specific point in time just before building the container, so that all the different codegen tasks occur together? Because if I use the WithCodeGeneration extension method multiple times, it will run multiple times. Or did I misunderstand this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's correct - code gen will run immediately, but not necessarily for one assembly at a time. The user has a degree of control over it.
In the following code, codegen is executed twice: once for IMyGrain's asm and MyGrain's asm and then again for whatever asms are in the app base dir. The second execution will see the code generated by the first, so it won't double-generate.
.ConfigureApplicationPartManager(parts =>
{
parts.AddApplicationPart(typeof(IMyGrain).Assembly)
.AddApplicationPart(typeof(MyGrain).Assembly)
.WithCodeGeneration();
parts.AddFromApplicationBaseDirectory().WithCodeGeneration();
});
The above code could execute codegen only once if the methods were all chained together instead of starting again from parts
.
Does that seem alright or would you prefer that all actions are queued up and executed only during Build()? That would add some complexity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it's fine if there is a way to chain everything and then execute once. And if they don't double-generate even when executing twice, then that's harmless anyway.
c343a03
to
3827e6c
Compare
99681bb
to
0ad25cf
Compare
@dotnet-bot test functional |
9aa25b9
to
3f1cb95
Compare
@dotnet-bot test functional |
/// </summary> | ||
/// <param name="manager">The builder.</param> | ||
/// <returns>A builder with support parts added.</returns> | ||
public static IApplicationPartManagerWithAssemblies WithCodeGeneration(this IApplicationPartManagerWithAssemblies manager) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should the return be void
. Otherwise it would be confusing what would happen if you keep chaining, wouldn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can call WithCodeGeneration().WithReferences(), for example - but we could make it void and force the order. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But what would that do? it's not clear to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should include those assemblies, generate code for them, and also include their references
t == typeof(string) || | ||
t == typeof(DateTime) || | ||
t == typeof(Decimal) || | ||
(t.IsArray && t.GetElementType().GetTypeInfo().IsOrleansPrimitive()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can probably avoid calling GetTypeInfo() since the extension method is now on Type
foreach (var parameter in typeInfo.GenericTypeParameters) | ||
{ | ||
foreach (var constraint in parameter.GetTypeInfo().GetGenericParameterConstraints()) | ||
{ | ||
if (IsSpecialClass(constraint)) return false; | ||
if (constraint == typeof(Array) || constraint == typeof(Delegate) || constraint == typeof(Enum)) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You dropped ValueType
when inlining. Was it by design?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is: it was supposed to tell us what types cannot be used as generic constraints in C#, but ValueType
can (T : struct
).
@@ -34,6 +34,7 @@ public KnownAssemblyAttribute(string assemblyName) | |||
/// serializable. | |||
/// </summary> | |||
/// <remarks>This is equivalent to specifying <see cref="KnownTypeAttribute"/> for all types.</remarks> | |||
[Obsolete("This property is no longer supported. Serializers will be generated for all accessible types.")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the reason for this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's simpler and less error prone to just consider all types in the few assemblies we're processing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But could be a lot more expensive now that runtime codegen is back, right? I'm not pushing back, just trying to understand
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be, since we need to perform accessibility checks for more types now. We cache those checks, though, so it shouldn't be an issue.
/// <param name="builder">The builder.</param> | ||
/// <param name="configure">The configuration delegate.</param> | ||
/// <returns>The builder.</returns> | ||
public static IClientBuilder ConfigureApplicationPartManager(this IClientBuilder builder, Action<IApplicationPartManager> configure) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about dropping Manager and just have ConfigureApplicationParts(...)
? It is using the manager under the hoods, but the user is configuring which parts the app will use (and of course it's less verbose)
/// <param name="builder">The builder.</param> | ||
/// <param name="assembly">The assembly.</param> | ||
/// <returns>The builder.</returns> | ||
public static ISiloHostBuilder AddApplicationPart(this ISiloHostBuilder builder, Assembly assembly) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm on the fence with this one. Do you envision this to be the most common case? Otherwise to make the jump to add references too for example, then it's a lot different, and maybe the best is to get them to use the fluent interface in the first place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm on the fence, too - should we just axe it? Shortcuts like this can be added later if we want, so maybe it's better to be conservative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My vote is yes: let's axe it for now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I wait for this change or you think we should keep it then?
c5c498e
to
96cd529
Compare
No description provided.