-
Notifications
You must be signed in to change notification settings - Fork 87
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
Add support for module initializers #992
base: draft-v9
Are you sure you want to change the base?
Changes from all commits
bafe4d9
5f65af0
dcf2475
3abc670
be3e2f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -526,6 +526,7 @@ | |
- `System.ObsoleteAttribute` ([§22.5.4](attributes.md#2254-the-obsolete-attribute)), which is used to mark a member as obsolete. | ||
- `System.Runtime.CompilerServices.AsyncMethodBuilderAttribute` ([§22.5.5](attributes.md#2255-the-asyncmethodbuilder-attribute)), which is used to establish a task builder for an async method. | ||
- `System.Runtime.CompilerServices.CallerLineNumberAttribute` ([§22.5.6.2](attributes.md#22562-the-callerlinenumber-attribute)), `System.Runtime.CompilerServices.CallerFilePathAttribute` ([§22.5.6.3](attributes.md#22563-the-callerfilepath-attribute)), and `System.Runtime.CompilerServices.CallerMemberNameAttribute` ([§22.5.6.4](attributes.md#22564-the-callermembername-attribute)), which are used to supply information about the calling context to optional parameters. | ||
- `System.Runtime.CompilerServices.ModuleInitializer` (§module-init-attr), which is used to mark a method as a module initializer. | ||
|
||
The Nullable static analysis attributes ([§22.5.7](attributes.md#2257-code-analysis-attributes)) can improve the correctness of warnings generated for nullabilities and null states ([§8.9.5](types.md#895-nullabilities-and-null-states)). | ||
|
||
|
@@ -860,6 +861,22 @@ | |
|
||
For invocations that occur within declarations of instance constructors, static constructors, finalizers and operators the member name used is implementation-dependent. | ||
|
||
### §module-init-attr The ModuleInitializer attribute | ||
|
||
The attribute `ModuleInitializer` is used to mark a method as a ***module initializer***. Such a method is called during initialization of the containing module. A module may have multiple initializers, which are called in an implementation-defined order. | ||
|
||
There are no limitations on what code is permitted in a module initializer. | ||
|
||
A module initializer shall have the following characteristics: | ||
|
||
- The *method_modifier* `static`. | ||
- No *parameter_list*. | ||
- A *return_type* of `void`. | ||
- No *type_parameter_list*. | ||
- Not be declared inside a *class_declaration* having a *type_parameter_list*. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not within a struct_declaration having a type_parameter_list, either. I think it's better to specify this as a semantic constraint "Not be a member of a generic type" than as a grammar constraint. |
||
- Be accessible from the containing module (that is, have an access modifier `internal` or `public`). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does that allow There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it does. The rules were chosen to describe "callable from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But how about: public class C {
private class D {
[System.Runtime.CompilerServices.ModuleInitializer]
public static void M() {
}
}
} The declaration of C.D.M() has the The wording might have to be changed again in the future when C# 11 file-local types are specified. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a really good point. |
||
- Not be a local function. | ||
Comment on lines
+870
to
+878
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In C# 11, this spec will also have to disallow |
||
|
||
### 22.5.7 Code analysis attributes | ||
|
||
#### 22.5.7.1 General | ||
|
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.
Not sure how much you want to repeat, but from https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#module-initializer:
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.
This part specifically is interesting:
Because there is no guarantee that the runtime will execute the initializer before using reflection to access types in the module, and in fact it does not, and this means that libraries can't use module initializers to hook up to AppDomain.AssemblyResolve in time to load assemblies required by such reflection. (Examples of wanting to do this is when assemblies are stored in nonstandard locations such as embedded resources or other places on disk, or when you need to handle assembly versioning differences and you can't use binding redirects. What all of these have in common are scenarios where a .NET library is a plugin to a third-party application.)