Skip to content

Commit 449b881

Browse files
authored
Add language reference and fundamentals for C# 14 extension members (#45654)
* Publish extensions specification Publish the feature specification for the extension members feature. * First draft of the language reference * Further edits for extensions Notes and code updates * update samples on enums * Finish all programming guide updates * fix build warnings * one more build warning * Finish edits on extension members * fix two build warnings * respond to feedback.
1 parent 1c9e9b6 commit 449b881

File tree

30 files changed

+939
-713
lines changed

30 files changed

+939
-713
lines changed

docfx.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@
5959
"first-class-span-types.md",
6060
"simple-lambda-parameters-with-modifiers.md",
6161
"partial-events-and-constructors.md",
62-
"null-conditional-assignment.md"
62+
"null-conditional-assignment.md",
63+
"extensions.md"
6364
],
6465
"src": "_csharplang/proposals",
6566
"dest": "csharp/language-reference/proposals",
@@ -510,7 +511,7 @@
510511
"_csharplang/proposals/csharp-11.0/*.md": "09/30/2022",
511512
"_csharplang/proposals/csharp-12.0/*.md": "08/15/2023",
512513
"_csharplang/proposals/csharp-13.0/*.md": "10/31/2024",
513-
"_csharplang/proposals/*.md": "04/04/2025",
514+
"_csharplang/proposals/*.md": "04/08/2025",
514515
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "11/08/2022",
515516
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "11/08/2023",
516517
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "11/09/2024",
@@ -691,6 +692,7 @@
691692
"_csharplang/proposals/simple-lambda-parameters-with-modifiers.md": "Simple lambda parameters with modifiers",
692693
"_csharplang/proposals/partial-events-and-constructors.md": "Partial events and constructors",
693694
"_csharplang/proposals/null-conditional-assignment.md": "Null conditional assignment",
695+
"_csharplang/proposals/extensions.md": "Extension members",
694696
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "C# compiler breaking changes since C# 10",
695697
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "C# compiler breaking changes since C# 11",
696698
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "C# compiler breaking changes since C# 12",
@@ -817,6 +819,7 @@
817819
"_csharplang/proposals/simple-lambda-parameters-with-modifiers.md": "This proposal allows lambda parameters to be declared with modifiers without requiring their type names. You can add modifiers like `ref` and `out` to lambda parameters without specifying their type.",
818820
"_csharplang/proposals/partial-events-and-constructors.md": "This proposal allows partial events and constructors to be declared in partial classes. The event and constructor can be split across class declarations.",
819821
"_csharplang/proposals/null-conditional-assignment.md": "This proposal allows the null conditional operator to be used for the destination of assignment expressions. This allows you to assign a value to a property or field only if the left side is not null.",
822+
"_csharplang/proposals/extensions.md": "This proposal enables new kinds of extension members. These new extension members support extension properties, extension static members, including extension operators.",
820823
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "Learn about any breaking changes since the initial release of C# 10 and included in C# 11",
821824
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "Learn about any breaking changes since the initial release of C# 11 and included in C# 12",
822825
"_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "Learn about any breaking changes since the initial release of C# 12 and included in C# 13",

docs/core/whats-new/dotnet-10/overview.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ C# 14 introduces several new features and enhancements to improve developer prod
8181
- **Unbound generic support for `nameof`**: The `nameof` expression now supports unbound generic types, such as `List<>`, returning the name of the type without requiring type arguments.
8282
- **Implicit span conversions**: Introduces first-class support for `Span<T>` and `ReadOnlySpan<T>` with new implicit conversions, enabling more natural programming with these types.
8383
- **Modifiers on simple lambda parameters**: Allows parameter modifiers like `ref`, `in`, or `out` in lambda expressions without specifying parameter types.
84-
- **Experimental feature - String literals in data section**: Enables emitting string literals as UTF-8 data into a separate section of the PE file, improving efficiency for certain scenarios.
8584
- **Partial events and constructors**: Adds support for partial instance constructors and partial events, complementing partial methods and properties introduced in C# 13.
8685
- **Extension members**: Extension methods now support static methods, instance properties, and static properties through `extension` blocks, enabling more flexible and powerful extensions.
8786
- **Null-conditional assignment**: Simplifies conditional assignments by allowing properties or fields to be updated only if the containing instance exists, using the `?.` operator.
87+
- **Experimental feature - String literals in data section**: Enables emitting string literals as UTF-8 data into a separate section of the PE file, improving efficiency for certain scenarios.
8888

8989
For more information, see [What's new in C# 14](../../../csharp/whats-new/csharp-14.md).
9090

docs/csharp/fundamentals/object-oriented/index.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "Classes, structs, and records"
33
description: Describes the use of classes, structures (structs), and records in C#.
4-
ms.date: 03/23/2022
4+
ms.date: 04/17/2025
55
helpviewer_keywords:
66
- "structs [C#], about structs"
77
- "records [C#], about records"
@@ -14,17 +14,17 @@ helpviewer_keywords:
1414
---
1515
# Overview of object oriented techniques in C\#
1616

17-
In C#, the definition of a type&mdash;a class, struct, or record&mdash;is like a blueprint that specifies what the type can do. An object is basically a block of memory that has been allocated and configured according to the blueprint. This article provides an overview of these blueprints and their features. The [next article in this series](objects.md) introduces objects.
17+
In C#, the definition of a type&mdash;a class, struct, or record&mdash;is like a blueprint that specifies what the type can do. An object is basically a block of memory allocated and configured according to the blueprint. This article provides an overview of these blueprints and their features. The [next article in this series](objects.md) introduces objects.
1818

1919
## Encapsulation
2020

21-
*Encapsulation* is sometimes referred to as the first pillar or principle of object-oriented programming. A class or struct can specify how accessible each of its members is to code outside of the class or struct. Methods and variables that aren't intended to be used from outside of the class or assembly can be hidden to limit the potential for coding errors or malicious exploits. For more information, see the [Object-oriented programming](../tutorials/oop.md) tutorial.
21+
*Encapsulation* is sometimes referred to as the first pillar or principle of object-oriented programming. A class or struct can specify how accessible each of its members is to code outside of the class or struct. Member not intended for consumers outside of the class or assembly are hidden to limit the potential for coding errors or malicious exploits. For more information, see the [Object-oriented programming](../tutorials/oop.md) tutorial.
2222

2323
## Members
2424

2525
The *members* of a type include all methods, fields, constants, properties, and events. In C#, there are no global variables or methods as there are in some other languages. Even a program's entry point, the `Main` method, must be declared within a class or struct (implicitly when you use [top-level statements](../program-structure/top-level-statements.md)).
2626

27-
The following list includes all the various kinds of members that may be declared in a class, struct, or record.
27+
The following list includes all the various kinds of members that can be declared in a class, struct, or record.
2828

2929
- Fields
3030
- Constants
@@ -56,7 +56,7 @@ The default accessibility is `private`.
5656

5757
Classes (but not structs) support the concept of inheritance. A class that derives from another class, called the *base class*, automatically contains all the public, protected, and internal members of the base class except its constructors and finalizers.
5858

59-
Classes may be declared as [abstract](../../language-reference/keywords/abstract.md), which means that one or more of their methods have no implementation. Although abstract classes cannot be instantiated directly, they can serve as base classes for other classes that provide the missing implementation. Classes can also be declared as [sealed](../../language-reference/keywords/sealed.md) to prevent other classes from inheriting from them.
59+
Classes can be declared as [abstract](../../language-reference/keywords/abstract.md), which means that one or more of their methods have no implementation. Although abstract classes can't be instantiated directly, they can serve as base classes for other classes that provide the missing implementation. Classes can also be declared as [sealed](../../language-reference/keywords/sealed.md) to prevent other classes from inheriting from them.
6060

6161
For more information, see [Inheritance](./inheritance.md) and [Polymorphism](./polymorphism.md).
6262

@@ -66,7 +66,7 @@ Classes, structs, and records can implement multiple interfaces. To implement fr
6666

6767
## Generic Types
6868

69-
Classes, structs, and records can be defined with one or more type parameters. Client code supplies the type when it creates an instance of the type. For example, the <xref:System.Collections.Generic.List%601> class in the <xref:System.Collections.Generic> namespace is defined with one type parameter. Client code creates an instance of a `List<string>` or `List<int>` to specify the type that the list will hold. For more information, see [Generics](../types/generics.md).
69+
Classes, structs, and records can be defined with one or more type parameters. Client code supplies the type when it creates an instance of the type. For example, the <xref:System.Collections.Generic.List%601> class in the <xref:System.Collections.Generic> namespace is defined with one type parameter. Client code creates an instance of a `List<string>` or `List<int>` to specify the type that the list holds. For more information, see [Generics](../types/generics.md).
7070

7171
## Static Types
7272

@@ -86,9 +86,9 @@ You can instantiate and initialize class or struct objects, and collections of o
8686

8787
## Anonymous Types
8888

89-
In situations where it isn't convenient or necessary to create a named class you use anonymous types. Anonymous types are defined by their named data members. For more information, see [Anonymous types](../types/anonymous-types.md).
89+
In situations where it isn't convenient or necessary to create a named class you use anonymous types. Named data members define anonymous types. For more information, see [Anonymous types](../types/anonymous-types.md).
9090

91-
## Extension Methods
91+
## Extension Members
9292

9393
You can "extend" a class without creating a derived class by creating a separate type. That type contains methods that can be called as if they belonged to the original type. For more information, see [Extension methods](../../programming-guide/classes-and-structs/extension-methods.md).
9494

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,34 @@
11
---
2-
title: "base keyword"
2+
title: "The base keyword"
33
description: Learn about the base keyword, which is used to access members of the base class from within a derived class in C#.
4-
ms.date: 07/20/2015
4+
ms.date: 04/17/2025
55
f1_keywords:
66
- "base"
77
- "BaseClass.BaseClass"
88
- "base_CSharpKeyword"
99
helpviewer_keywords:
1010
- "base keyword [C#]"
11-
ms.assetid: 8b645dbe-1a33-49b8-8716-1c401f9a5ea5
1211
---
13-
# base (C# Reference)
12+
# The base keyword
1413

1514
The `base` keyword is used to access members of the base class from within a derived class. Use it if you want to:
1615

17-
- Call a method on the base class that has been overridden by another method.
18-
16+
- Call a method on the base class overridden by another method.
1917
- Specify which base-class constructor should be called when creating instances of the derived class.
2018

21-
The base class access is permitted only in a constructor, in an instance method, and in an instance property accessor.
22-
23-
Using the `base` keyword from within a static method will give an error.
19+
The base class access is permitted only in a constructor, in an instance method, and in an instance property accessor. Using the `base` keyword from within a static method produces an error.
2420

2521
The base class that is accessed is the base class specified in the class declaration. For example, if you specify `class ClassB : ClassA`, the members of ClassA are accessed from ClassB, regardless of the base class of ClassA.
2622

27-
## Example 1
28-
29-
In this example, both the base class `Person` and the derived class `Employee` have a method named `GetInfo`. By using the `base` keyword, it is possible to call the `GetInfo` method of the base class from within the derived class.
23+
In this example, both the base class `Person` and the derived class `Employee` have a method named `GetInfo`. By using the `base` keyword, it's possible to call the `GetInfo` method of the base class from within the derived class.
3024

31-
[!code-csharp[csrefKeywordsAccess#1](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsAccess/CS/csrefKeywordsAccess.cs#1)]
32-
33-
For additional examples, see [new](new-modifier.md), [virtual](virtual.md), and [override](override.md).
34-
35-
## Example 2
25+
:::code language="csharp" source="./snippets/csrefKeywordsAccess.cs" id="snippet1":::
3626

3727
This example shows how to specify the base-class constructor called when creating instances of a derived class.
3828

39-
[!code-csharp[csrefKeywordsAccess#2](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsAccess/CS/csrefKeywordsAccess.cs#2)]
29+
:::code language="csharp" source="./snippets/csrefKeywordsAccess.cs" id="snippet2":::
30+
31+
For more examples, see [new](new-modifier.md), [virtual](virtual.md), and [override](override.md).
4032

4133
## C# language specification
4234

@@ -45,4 +37,4 @@ This example shows how to specify the base-class constructor called when creatin
4537
## See also
4638

4739
- [C# Keywords](./index.md)
48-
- [this](./this.md)
40+
- [The `this` keyword](./this.md)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
title: "Extension member declarations"
3+
description: "Learn the syntax to declare extension members in C#. Extension members enable you to add functionality to types and interfaces in those instances where you don't have the source for the original type. Extensions are often paired with generic interfaces to implement a common set of functionality across all types that implement that interface."
4+
ms.date: 04/17/2025
5+
f1_keywords:
6+
- "extension_CSharpKeyword"
7+
- "extension"
8+
---
9+
# Extension declaration (C# Reference)
10+
11+
Beginning with C# 14, top level, nongeneric `static class` declarations can use `extension` containers to declare *extension members*. Extension members are methods or properties and can appear to be instance or static members. Earlier versions of C# enable *extension methods* by adding `this` as a modifier to the first parameter of a static method declared in a top-level, nongeneric static class.
12+
13+
The `extension` block specifies the type and receiver for extension members. You can declare methods and properties inside the `extension` declaration. The following example declares a single extension block that defines an instance extension method and an instance property.
14+
15+
:::code language="csharp" source="./snippets/extensions.cs" id="ExtensionMembers":::
16+
17+
The `extension` defines the receiver: `sequence`, which is an `IEnumerable<int>`. The receiver type can be nongeneric, an open generic, or a closed generic type. The name `sequence` is in scope in every instance member declared in that extension. The extension method and property both access `sequence`.
18+
19+
Any of the extension members can be accessed as though they were members of the receiver type:
20+
21+
:::code language="csharp" source="./snippets/extensions.cs" id="UseExtensionMethod":::
22+
23+
You can declare any number of members in a single container, as long as they share the same receiver. You can declare as many extension blocks in a single class as well. Different extensions don't need to declare the same type or name of receiver. The extension parameter doesn't need to include the parameter name if the only members are static:
24+
25+
:::code language="csharp" source="./snippets/extensions.cs" id="StaticExtensions":::
26+
27+
Static extensions can be called as though they're static members of the receiver type:
28+
29+
:::code language="csharp" source="./snippets/extensions.cs" id="UseStaticExtensions":::
30+
31+
> [!IMPORTANT]
32+
> An extension doesn't introduce a *scope* for member declarations. All members declared in a single class, even if in multiple extensions, must have unique signatures. The generated signature includes the receiver type in its name for static members and the receiver parameter for extension instance members.
33+
34+
The following example shows an extension method using the `this` modifier:
35+
36+
:::code language="csharp" source="./snippets/ExtensionMethods.cs" id="ExtensionMethod":::
37+
38+
The `Add` method can be called from any other method as though it was a member of the `IEnumerable<int>` interface:
39+
40+
:::code language="csharp" source="./snippets/ExtensionMethods.cs" id="UseExtensionMethod":::
41+
42+
Both forms of extension methods generate the same intermediate language (IL). Callers can't make a distinction between them. In fact, you can convert existing extension methods to the new member syntax without a breaking change. The formats are both binary and source compatible.
43+
44+
## Generic extension blocks
45+
46+
Where you specify the type parameters for an extension member declared in an extension block depends on where that type parameter is required:
47+
48+
- You add the type parameter to the `extension` declaration when the type parameter is used in the receiver.
49+
- You add the type parameter to the member declaration when the type is distinct from any type parameter specified on the receiver.
50+
- You can't specify the same type parameter in both locations.
51+
52+
The following example shows an extension block for `IEnumerable<T>` where two of the extension members require a second type parameter:
53+
54+
:::code language="csharp" source="./snippets/extensions.cs" id="GenericExtension":::
55+
56+
The members `Append` and `Prepend` specify the *extra* type parameter for the conversion. None of the members repeat the type parameter for the receiver.
57+
58+
The equivalent extension method declarations demonstrate how those type parameters are encoded:
59+
60+
:::code language="csharp" source="./snippets/ExtensionMethods.cs" id="GenericExtensionMethods":::
61+
62+
## See also
63+
64+
- [Extensions feature specification](~/_csharplang/proposals/extensions.md)
65+
66+
## C# language specification
67+
68+
[!INCLUDE[CSharplangspec](~/includes/csharplangspec-md.md)]

0 commit comments

Comments
 (0)