69 lines
3 KiB
Markdown
69 lines
3 KiB
Markdown
# Module Initializers
|
|
|
|
* [x] Proposed
|
|
* [ ] Prototype: [In Progress](https://github.com/jnm2/roslyn/tree/module_initializer)
|
|
* [ ] Implementation: [In Progress](https://github.com/dotnet/roslyn/tree/features/module-initializers)
|
|
* [ ] Specification: [Not Started]()
|
|
|
|
## Summary
|
|
[summary]: #summary
|
|
|
|
Although the .NET platform has a [feature](https://github.com/dotnet/runtime/blob/master/docs/design/specs/Ecma-335-Augments.md#module-initializer) that directly supports writing initialization code for the assembly (technically, the module), it is not exposed in C#. This is a rather niche scenario, but once you run into it the solutions appear to be pretty painful. There are reports of [a number of customers](https://www.google.com/search?q=.net+module+constructor+c%23&oq=.net+module+constructor) (inside and outside Microsoft) struggling with the problem, and there are no doubt more undocumented cases.
|
|
|
|
## Motivation
|
|
[motivation]: #motivation
|
|
|
|
- Enable libraries to do eager, one-time initialization when loaded, with minimal overhead and without the user needing to explicitly call anything
|
|
- One particular pain point of current `static` constructor approaches is that the runtime must do additional checks on usage of a type with a static constructor, in order to decide whether the static constructor needs to be run or not. This adds measurable overhead.
|
|
- Enable source generators to run some global initialization logic without the user needing to explicitly call anything
|
|
|
|
## Detailed design
|
|
[design]: #detailed-design
|
|
|
|
A method can be designated as a module initializer by decorating it with a `[ModuleInitializer]` attribute.
|
|
|
|
```cs
|
|
using System;
|
|
namespace System.Runtime.CompilerServices
|
|
{
|
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
|
public sealed class ModuleInitializerAttribute : Attribute { }
|
|
}
|
|
```
|
|
|
|
The attribute can be used like this:
|
|
|
|
```cs
|
|
using System.Runtime.CompilerServices;
|
|
class C
|
|
{
|
|
[ModuleInitializer]
|
|
internal static void M1()
|
|
{
|
|
// ...
|
|
}
|
|
}
|
|
```
|
|
|
|
Some requirements are imposed on the method targeted with this attribute:
|
|
1. The method must be `static`.
|
|
1. The method must be parameterless.
|
|
1. The method must return `void`.
|
|
1. The method must not be generic or be contained in a generic type.
|
|
1. The method must be accessible from the containing module.
|
|
- This means the method's effective accessibility must be `internal` or `public`.
|
|
- This also means the method cannot be a local function.
|
|
|
|
When one or more valid methods with this attribute are found in a compilation, the compiler will emit a module initializer which calls each of the attributed methods. The calls will be emitted in a reserved, but deterministic order.
|
|
|
|
## Drawbacks
|
|
[drawbacks]: #drawbacks
|
|
|
|
Why should we *not* do this?
|
|
|
|
- Perhaps the existing third-party tooling for "injecting" module initializers is sufficient for users who have been asking for this feature.
|
|
|
|
## Design meetings
|
|
|
|
### [April 8th, 2020](/meetings/2020/LDM-2020-04-08.md#module-initializers)
|