-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
[API Proposal] Add persist able AssemblyBuilder implementation #83988
Comments
Tagging subscribers to this area: @dotnet/area-system-reflection Issue DetailsContributes to Support equivalent of AssemblyBuilder.Save to save in-memory IL to an assembly As per #62956 we plan to a add managed implementation of Initial version would only support Save, no Run, therefore the factory method not accepting namespace System.Reflection.Emit
{
+ public sealed class PersistableAssemblyBuilder : AssemblyBuilder
+ {
+ internal PersistableAssemblyBuilder (AssemblyName name, IEnumerable<CustomAttributeBuilder>? assemblyAttributes) { }
// New static methods without AssemblyBuilderAccess, because initial version will only support Save
+ public static PersistableAssemblyBuilder DefineDynamicAssembly(AssemblyName name) { throw null; }
+ public static PersistableAssemblyBuilder DefineDynamicAssembly(AssemblyName name, Enumerable<CustomAttributeBuilder>? assemblyAttributes) { throw null; }
// New instance methods
+ public void Save(Stream stream) { }
+ public void Save(string assemblyFileName) { } // same as in .NET Framework
+ }
} Usage exampleusing System.Reflection.Emit;
public class MyType
{
public void MyMethod(AssemblyName assemblyName, string fileName)
{
PersistableAssemblyBuilder builder = PersistableAssemblyBuilder.DefineDynamicAssembly(assemblyName);
// ... Add module and other members
builder.Save(fileName);
}
} Alternative designSupport for namespace System.Reflection.Emit
{
+ public sealed class PersistableAssemblyBuilder : AssemblyBuilder
+ {
+ internal PersistableAssemblyBuilder (AssemblyName name, IEnumerable<CustomAttributeBuilder>? assemblyAttributes) { }
+ public static new PersistableAssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access) { throw null; }
+ public static new PersistableAssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access, Enumerable<CustomAttributeBuilder>? assemblyAttributes) { throw null; }
// New instance methods
+ public void Save(Stream stream) { }
+ public void Save(string assemblyFileName) { } // same as in .NET Framework
+ }
[Flags]
public enum AssemblyBuilderAccess
{
Run = 1,
+ Save = 2,
RunAndCollect = 8 | Run,
}
} Usage exampleusing System.Reflection.Emit;
public class MyType
{
public void MyMethod(AssemblyName assemblyName, string fileName)
{
PersistableAssemblyBuilder builder = PersistableAssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
// ... Add module and other members
builder.Save(fileName);
}
}
|
Tagging subscribers to this area: @dotnet/area-system-reflection-emit Issue DetailsContributes to Support equivalent of AssemblyBuilder.Save to save in-memory IL to an assembly As per #62956 we plan to a add managed implementation of Initial version would only support Save, no Run, therefore the factory method not accepting namespace System.Reflection.Emit
{
+ public sealed class PersistableAssemblyBuilder : AssemblyBuilder
+ {
+ internal PersistableAssemblyBuilder (AssemblyName name, IEnumerable<CustomAttributeBuilder>? assemblyAttributes) { }
// New static methods without AssemblyBuilderAccess, because initial version will only support Save
+ public static PersistableAssemblyBuilder DefineDynamicAssembly(AssemblyName name) { throw null; }
+ public static PersistableAssemblyBuilder DefineDynamicAssembly(AssemblyName name, Enumerable<CustomAttributeBuilder>? assemblyAttributes) { throw null; }
// New instance methods
+ public void Save(Stream stream) { }
+ public void Save(string assemblyFileName) { } // same as in .NET Framework
+ }
} Usage exampleusing System.Reflection.Emit;
public class MyType
{
public void MyMethod(AssemblyName assemblyName, string fileName)
{
PersistableAssemblyBuilder builder = PersistableAssemblyBuilder.DefineDynamicAssembly(assemblyName);
// ... Add module and other members
builder.Save(fileName);
}
} Alternative designSupport for namespace System.Reflection.Emit
{
+ public sealed class PersistableAssemblyBuilder : AssemblyBuilder
+ {
+ internal PersistableAssemblyBuilder (AssemblyName name, IEnumerable<CustomAttributeBuilder>? assemblyAttributes) { }
+ public static new PersistableAssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access) { throw null; }
+ public static new PersistableAssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access, Enumerable<CustomAttributeBuilder>? assemblyAttributes) { throw null; }
// New instance methods
+ public void Save(Stream stream) { }
+ public void Save(string assemblyFileName) { } // same as in .NET Framework
+ }
[Flags]
public enum AssemblyBuilderAccess
{
Run = 1,
+ Save = 2,
RunAndCollect = 8 | Run,
}
} Usage exampleusing System.Reflection.Emit;
public class MyType
{
public void MyMethod(AssemblyName assemblyName, string fileName)
{
PersistableAssemblyBuilder builder = PersistableAssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
// ... Add module and other members
builder.Save(fileName);
}
}
|
Another alternative is add Save methods and abstract SaveCore method on the AssemblyBuilder. |
Are you suggesting adding namespace System.Reflection.Emit
{
public abstract class AssemblyBuilder : Assembly
{
+ public void Save(Stream stream) { }
+ public void Save(string assemblyFileName) { } // same as in .NET Framework
+ protected abstract void SaveCore(Stream stream);
}
[Flags]
public enum AssemblyBuilderAccess
{
Run = 1,
+ Save = 2,
RunAndCollect = 8 | Run,
}
} Usage exampleusing System.Reflection.Emit;
public class MyType
{
public void MyMethod(AssemblyName assemblyName, string fileName)
{
AssemblyBuilder builder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
// ... Add module and other members
builder.Save(fileName);
}
} The problem with that design is it would need reflection in order to create persist able |
In the fulness of time, we want to use the managed assembly builder for both the persistent and non-persistent modes. We will need reflection for the non-persisted mode since the API for that is in CoreLib already. I do not see a problem with using reflection for the persistent mode as well. For the persistent mode, we may want to have argument that specifies the core assembly - to address https://github.com/dotnet/runtime/pull/83554/files#diff-c12b00ae2e7f16430a305235a8e8ea053806a0d3fc4b15ea4e18f5c0cb904cfaR40 TODO, similar to how MetadataLoadContext takes |
Yes, reflection needed for persistent mode only
OK, adding this approach as an alternative design
Sounds good, if that is the case, we can add overloads to public abstract class AssemblyBuilder : Assembly
{
+ public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access, string? coreAssemblyName = null) { throw null; }
+ public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access, Enumerable<CustomAttributeBuilder>? assemblyAttributes, string? coreAssemblyName = null) { throw null; }
} |
With these two points incorporated, the design would be: class AssemblyBuilder
{
// Existing APIs
[RequiresDynamicCode("Defining a dynamic assembly requires dynamic code.")]
public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access);
[RequiresDynamicCode("Defining a dynamic assembly requires dynamic code.")]
public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access, System.Collections.Generic.IEnumerable<CustomAttributeBuilder>? assemblyAttributes);
+ // New API - note that it does not have RequiresDynamicCode annotation
+ public static AssemblyBuilder DefinePersistedAssembly(AssemblyName name, Assembly coreAssembly, IEnumerable<CustomAttributeBuilder>? assemblyAttributes = null);
+ public void Save(Stream stream) { }
+ public void Save(string assemblyFileName) { } // same as in .NET Framework
+ protected abstract void SaveCore(Stream stream);
} |
That looks nice and simple / streamlined. |
With both factory APIs ( |
I do not see any trimming problems with that design. We just need to follow the patterns recognized by the linker. |
Per offline discussion, as long as a string literal is used with Type.GetType("System.Reflection.Emit.PersistableAssemblyBuilder, System.Reflection.Emit") |
Thank you for your feedbacks! Updated the description accordingly. |
namespace System.Reflection.Emit;
public partial class AssemblyBuilder
{
// Existing APIs
// [RequiresDynamicCode("Defining a dynamic assembly requires dynamic code.")]
// public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access);
// [RequiresDynamicCode("Defining a dynamic assembly requires dynamic code.")]
// public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access, System.Collections.Generic.IEnumerable<CustomAttributeBuilder>? assemblyAttributes);
// New API - note that it does not have RequiresDynamicCode annotation
public static AssemblyBuilder DefinePersistedAssembly(AssemblyName name, Assembly coreAssembly, IEnumerable<CustomAttributeBuilder>? assemblyAttributes = null);
public void Save(Stream stream);
public void Save(string assemblyFileName);
protected abstract void SaveCore(Stream stream);
} |
Fixed with #97177 |
Contributes to Support equivalent of AssemblyBuilder.Save to save in-memory IL to an assembly
As per #62956 we plan to a add managed implementation of
AssemblyBuilder
that could save in-memory IL to an assembly file/stream.Proposed design 1
Initial version would only support Save, no Run, therefore the factory method not accepting
AssemblyBuilderAccess
that defines the access mode for the assembly. It is the current prototype design.Usage example
Alternative design 2:
The new persisted AssemblyBuilder type implementation will not exposed, instead we add
Save
into the abstract class AssemblyBuilder andprotected abstract SaveCore
method for implementation. Use the same factory method for creating AssemblyBuilder. This need for using reflection in order to create persisted AssemblyBuilder.Usage example
Alternative design 3:
Comment by @jkotas for above
Alternative design 2
:With these two points incorporated, the design would be:
AssemblyBuilderAccess
is not used in this design because it will only support "Save" initially and eventually we allowRun
without requiring to specifySave/Run
explicitly.Usage example
The text was updated successfully, but these errors were encountered: