Skip to content

Commit c032a2d

Browse files
BillWagnerjcouvgewarren
authored
Update docs output for extensions (#9346)
* 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>
1 parent c2bfa0b commit c032a2d

File tree

1 file changed

+73
-12
lines changed

1 file changed

+73
-12
lines changed

meetings/working-groups/extensions/Extension-API-docs.md

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ Extensions introduce new requirements for our API reference pipeline. The additi
55
- 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.
66
- Readers need to know if the receiver is an instance of a type, or the type itself.
77
- 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.
99

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.
1111

1212
## Existing Extension methods
1313

@@ -63,7 +63,7 @@ The presentation for C# 14 extensions needs to account for several new types of
6363

6464
This proposal currently assumes no changes to the presentation for existing extension methods.
6565

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.
6767
6868
### Extension member prototypes
6969

@@ -143,21 +143,82 @@ There should be a new style for extension members. This should be modeled after
143143

144144
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.
145145

146-
### Unspeakable extension type
146+
### Unspeakable extension skeletons
147147

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:
149149

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.
151152

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.
155154

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.
157156

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+
static class E
160+
{
161+
/// <summary>Summary for extension block</summary>
162+
/// <typeparam name="T">Description for T</typeparam>
163+
/// <param name="t">Description for t</param>
164+
extension<T>(T t)
165+
{
166+
/// <summary>Summary for M</summary>
167+
/// <typeparam name="U">Description for U</typeparam>
168+
/// <param name="u">Description for u</param>
169+
public void M<U>(U u) => throw null!;
170+
171+
/// <summary>Summary for P</summary>
172+
public int P => 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+
<member name="T:E">
187+
<summary>Summary for E</summary>
188+
</member>
189+
<member name="T:E.<>E__0`1">
190+
<summary>Summary for extension block</summary>
191+
<typeparam name="T">Description for T</typeparam>
192+
<param name="t">Description for t</param>
193+
</member>
194+
<member name="M:E.<>E__0`1.M``1(``0)">
195+
<summary>Summary for M</summary>
196+
<typeparam name="U">Description for U</typeparam>
197+
<param name="u">Description for u</param>
198+
</member>
199+
<member name="P:E.<>E__0`1.P">
200+
<summary>Summary for P</summary>
201+
</member>
202+
<member name="M:E.M``2(``0,``1)">
203+
<inheritdoc cref="M:E.<>E__0`1.M``1(``0)"/>
204+
</member>
205+
<member name="M:E.get_P``1(``0)">
206+
<inheritdoc cref="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.
159220

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).
161222

162223
## Disambiguation and API docs
163224

0 commit comments

Comments
 (0)