You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Update docs output
Recent decisions in LDM and dotnet/roslyn#78365 change how XML output is generated and should be consumed.
* Proofread and clarify
* Apply suggestions from code review
Co-authored-by: Julien Couvreur <jcouv@microsoft.com>
* respond to feedback.
* Apply suggestions from code review
Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com>
* Respond to feedback.
---------
Co-authored-by: Julien Couvreur <jcouv@microsoft.com>
Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com>
Copy file name to clipboardExpand all lines: meetings/working-groups/extensions/Extension-API-docs.md
+73-12Lines changed: 73 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,9 +5,9 @@ Extensions introduce new requirements for our API reference pipeline. The additi
5
5
- The docs term is "Extension Methods". That term currently means "extension methods with an instance receiver". Now, extensions can be properties, indexers, or operators. These extension members can be accessed as either an instance member on the extended type, or as a static member on the extended type.
6
6
- Readers need to know if the receiver is an instance of a type, or the type itself.
7
7
- Readers occasionally need to know the class name of holding the extension, typically for disambiguation.
8
-
- The extension container becomes an unspeakable name, and it should be elided in documentation.
8
+
- The extension block is emitted as a nested class with skeleton members and XML doc comments. The nested class is given an unspeakable name.
9
9
10
-
The new extensions experience should be built on the framework used for the existing extension methods. The document describes the new experience as a set of enhancements to the existing extension method documentation.
10
+
The new extensions experience should be built on the framework used for the existing extension methods. In fact, when a new extension member is a method whose receiver is an instance, both forms are binary compatible. The document describes the new experience as a set of enhancements to the existing extension method documentation.
11
11
12
12
## Existing Extension methods
13
13
@@ -63,7 +63,7 @@ The presentation for C# 14 extensions needs to account for several new types of
63
63
64
64
This proposal currently assumes no changes to the presentation for existing extension methods.
65
65
66
-
> Alternative: [Compatibility with existing extension methods](./compat-mode-in-extensions.md) is still subject to [refinement](./Compatibility%20through%20coexistence%20between%20extension%20types%20and%20extension%20methods.md). One proposal makes existing extension methods indistinguishable from new extension members when consumed. If that proposal is adopted, we should experiment with displaying all extension members using this updated format. Readers can give feedback on whether they prefer a unified presentation, or want to know if a method follows the new or old format.
66
+
> Alternative: We could experiment with displaying all extension members using this updated format. Readers can give feedback on whether they prefer a unified presentation, or want to know if a method follows the new or old format. There is no reason a consumer needs to know which format was used to declare an extension. The declarations are binary compatible.
67
67
68
68
### Extension member prototypes
69
69
@@ -143,21 +143,82 @@ There should be a new style for extension members. This should be modeled after
143
143
144
144
The emphasis on the receiver parameter reinforces the new syntax, and is necessary for readers to see the extended type on the new extension member.
145
145
146
-
### Unspeakable extension type
146
+
### Unspeakable extension skeletons
147
147
148
-
The compiler generates a nested type with an unspeakable name, and an unspeakable member, for each extension container. See the example under [implementation](https://github.com/dotnet/csharplang/blob/main/proposals/extensions.md#implementations) in the feature spec.
148
+
The compiler generates a public skeleton class that defines prototypes for extension members. The skeleton class has an unspeakable name and contains the following prototypes:
149
149
150
-
The unspeakable nested type requires the following behavior:
150
+
- A private static unspeakable method declaration starting with `<Extension>`. This private static method includes one parameter that represents the receiver for the extension members declared in the skeleton.
151
+
- Prototypes for all extension members defined for the receiver. These prototypes show the declarations as though declared on the receiver type.
151
152
152
-
- The unspeakable type, for example `<>E__1<T>`, should not be displayed in the API docs.
153
-
- The unspeakable member, for example `public static <Extension>$(IEnumerable<T> source)` should not be displayed in the API docs. However, the single parameter for this method defines the receiver type and name for all extensions in this container.
154
-
- The public members of the unspeakable nested class provides the prototypes for all extensions. Those are important in the docs.
153
+
The unspeakable skeleton provides the prototypes for the extension members and the receiver type. The nodes of the skeleton provide a location for the XML output from the `///` comments on the extension members and the receiver parameter. The `///` comments on the extension declaration are written as XML on the node for the unspeakable member declaring the receiver. The `///` comments on each extension member are written as XML on the node for the embedded member of the unspeakable containing class.
155
154
156
-
### XML comments on the receiver parameter
155
+
See the following code and XML for an example of extension members and the resulting XML output.
157
156
158
-
Developers use the `<param>` and (optionally) `<typeparam>` tags on the `extension` container to provide information about the receiver type.
157
+
```csharp
158
+
/// <summary>Summary for E</summary>
159
+
staticclassE
160
+
{
161
+
/// <summary>Summary for extension block</summary>
162
+
/// <typeparamname="T">Description for T</typeparam>
163
+
/// <paramname="t">Description for t</param>
164
+
extension<T>(T t)
165
+
{
166
+
/// <summary>Summary for M</summary>
167
+
/// <typeparamname="U">Description for U</typeparam>
168
+
/// <paramname="u">Description for u</param>
169
+
publicvoidM<U>(Uu) =>thrownull!;
170
+
171
+
/// <summary>Summary for P</summary>
172
+
publicintP=>0;
173
+
}
174
+
}
175
+
```
176
+
177
+
produces the following XML output:
178
+
179
+
```xml
180
+
<?xml version="1.0"?>
181
+
<doc>
182
+
<assembly>
183
+
<name>Test</name>
184
+
</assembly>
185
+
<members>
186
+
<membername="T:E">
187
+
<summary>Summary for E</summary>
188
+
</member>
189
+
<membername="T:E.<>E__0`1">
190
+
<summary>Summary for extension block</summary>
191
+
<typeparamname="T">Description for T</typeparam>
192
+
<paramname="t">Description for t</param>
193
+
</member>
194
+
<membername="M:E.<>E__0`1.M``1(``0)">
195
+
<summary>Summary for M</summary>
196
+
<typeparamname="U">Description for U</typeparam>
197
+
<paramname="u">Description for u</param>
198
+
</member>
199
+
<membername="P:E.<>E__0`1.P">
200
+
<summary>Summary for P</summary>
201
+
</member>
202
+
<membername="M:E.M``2(``0,``1)">
203
+
<inheritdoccref="M:E.<>E__0`1.M``1(``0)"/>
204
+
</member>
205
+
<membername="M:E.get_P``1(``0)">
206
+
<inheritdoccref="P:E.<>E__0`1.P"/>
207
+
</member>
208
+
</members>
209
+
</doc>
210
+
```
211
+
212
+
### XML Output for `///` comments
213
+
214
+
The compiler uses the skeleton declarations to produce the XML output for all `///` comments on the extension node and the embedded extension members:
215
+
216
+
- Comments from the `extension` block are applied to the embedded receiver field in the unspeakable nested class. This can include type parameter information and parameter information for the receiver.
217
+
- Comments from extension members are output to the skeleton prototypes embedded in the unspeakable nested class.
218
+
- Any extension member declaration that includes `typeparamref` or `paramref` nodes in the extension block resolve to the corresponding `typeparam` and `param` nodes on the extension block.
219
+
- The implementation nodes for the extension members use the `<inheritdoc cref="skeleton-member" />` node to point to the generated XML output from the skeleton member.
159
220
160
-
The compiler needs to emit these nodes somewhere in the XML output. Suggestion: On the unspeakable member that notes the receiver. The pipeline needs to read that XML and emit the proper HTML.
221
+
The nodes on the receiver and each member must be merged by the tools that consume the XML (for example, Visual Studio IntelliSense, or the MS Learn build process).
0 commit comments