Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions docs/csharp/language-reference/keywords/extension.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Extension member declarations"
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."
ms.date: 01/21/2026
ms.date: 07/08/2026
f1_keywords:
- "extension_CSharpKeyword"
- "extension"
Expand All @@ -12,7 +12,7 @@ Starting with C# 14, top-level, nongeneric `static class` declarations can use `

[!INCLUDE[csharp-version-note](../includes/initial-version.md)]

The `extension` block specifies the type and receiver for extension members. You can declare methods, properties, or operators inside the `extension` declaration. The following example declares a single extension block that defines an instance extension method, an instance property, and a static operator method.
The `extension` block specifies the type and receiver for extension members. You can declare methods, properties, indexers, and operators inside the `extension` declaration. The following example declares a single extension block that defines an instance extension method, an instance property, and a static operator method.

> [!NOTE]
> All the examples in this article include XML comments for the members and the extension block. The node on the `extension` block describes the extended type and the receiver parameter. The C# compiler copies this node to the generated member for all members in the extension block. These examples demonstrate the preferred style for generating XML documentation for extension members.
Expand Down Expand Up @@ -66,9 +66,22 @@ The equivalent extension method declarations demonstrate how those type paramete

:::code language="csharp" source="./snippets/ExtensionMethods.cs" id="GenericExtensionMethods":::

## Extension indexers

Starting with C# 15, you can declare *indexers* in an `extension` block. An extension indexer lets you index into a receiver as though the indexer were declared on the receiver type. Because indexers are always instance members, an extension block that declares an indexer must provide a named receiver parameter. Extension indexers support the same features as ordinary indexers, including `get` and `set` accessors, expression-bodied accessors, and ref-returning accessors.

The following example declares a get-only indexer on `IEnumerable<int>` that returns the element at a specified position:

:::code language="csharp" source="./snippets/extensions.cs" id="ExtensionIndexer":::

You index into the receiver as though the indexer were a member of the receiver type:

:::code language="csharp" source="./snippets/extensions.cs" id="UseExtensionIndexer":::

## See also

- [Extensions feature specification](~/_csharplang/proposals/csharp-14.0/extensions.md)
- [Extension indexers feature specification](~/_csharplang/proposals/extension-indexers.md)

## C# language specification

Expand Down
26 changes: 26 additions & 0 deletions docs/csharp/language-reference/keywords/snippets/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,28 @@
}
// </GenericExtension>

// <ExtensionIndexer>
/// <summary>
/// Contains an extension indexer for numeric sequences.
/// </summary>
public static class SequenceIndexer
{
/// <summary>
/// Defines an indexer for integer sequences.
/// </summary>
/// <param name="sequence">The sequence used as a receiver.</param>
extension(IEnumerable<int> sequence)
{
/// <summary>
/// Gets the element at the specified position in the sequence.
/// </summary>
/// <param name="index">The zero-based position of the element to retrieve.</param>
/// <value>The element at the specified position.</value>
public int this[int index] => sequence.ElementAt(index);

Check failure on line 222 in docs/csharp/language-reference/keywords/snippets/Extensions.cs

View workflow job for this annotation

GitHub Actions / snippets-build

D:\a\docs\docs\docs\csharp\language-reference\keywords\snippets\Extensions.cs(222,20): error CS9282: This member is not allowed in an extension block [D:\a\docs\docs\docs\csharp\language-reference\keywords\snippets\keywords_pb0btawu_wpftmp.csproj]

Check failure on line 222 in docs/csharp/language-reference/keywords/snippets/Extensions.cs

View workflow job for this annotation

GitHub Actions / snippets-build

This member is not allowed in an extension block

Check failure on line 222 in docs/csharp/language-reference/keywords/snippets/Extensions.cs

View workflow job for this annotation

GitHub Actions / snippets-build

This member is not allowed in an extension block

Check failure on line 222 in docs/csharp/language-reference/keywords/snippets/Extensions.cs

View workflow job for this annotation

GitHub Actions / snippets-build

This member is not allowed in an extension block
}
}
// </ExtensionIndexer>

public static class ExtensionExamples
{
public static void BasicExample()
Expand All @@ -219,5 +241,9 @@
var newSequence = IEnumerable<int>.Generate(5, 10, 2);
var identity = IEnumerable<int>.Identity;
// </UseStaticExtensions>

// <UseExtensionIndexer>
int third = numbers[2];
// </UseExtensionIndexer>
}
}
7 changes: 7 additions & 0 deletions docs/csharp/language-reference/xmldoc/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ Add XML comments for `<summary>`, `<param>`, and, if necessary, `<typeparam>` to

The C# compiler copies the XML nodes from the `extension` block to all members declared in that block.

For an extension indexer, `cref` syntax can reference the indexer and its accessors through the `extension` block that declares it, and it can reference the implementation methods on the containing class. The following examples show how to reference the `this[int]` indexer and its generated `get_Item` accessor from the preceding example:

```csharp
/// <seealso cref="Extensions.extension{TSequence}(System.Collections.Generic.IEnumerable{TSequence}).this[int]"/>
/// <seealso cref="Extensions.extension{TSequence}(System.Collections.Generic.IEnumerable{TSequence}).get_Item(int)"/>
```

## Math class example

The following code shows a realistic example of adding doc comments to a math library.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,13 @@
yield return generator();
}
}

/// <summary>
/// Gets the element at the specified position in the sequence.
/// </summary>
/// <param name="index">The zero-based position of the element to retrieve.</param>
/// <value>The element at the specified position.</value>
public TSequence this[int index] => sequence.ElementAt(index);

Check failure on line 371 in docs/csharp/language-reference/xmldoc/snippets/xmldoc/DocComments.cs

View workflow job for this annotation

GitHub Actions / snippets-build

D:\a\docs\docs\docs\csharp\language-reference\xmldoc\snippets\xmldoc\DocComments.cs(371,26): error CS9282: This member is not allowed in an extension block [D:\a\docs\docs\docs\csharp\language-reference\xmldoc\snippets\xmldoc\xmldoc.csproj]

Check failure on line 371 in docs/csharp/language-reference/xmldoc/snippets/xmldoc/DocComments.cs

View workflow job for this annotation

GitHub Actions / snippets-build

This member is not allowed in an extension block

Check failure on line 371 in docs/csharp/language-reference/xmldoc/snippets/xmldoc/DocComments.cs

View workflow job for this annotation

GitHub Actions / snippets-build

This member is not allowed in an extension block

Check failure on line 371 in docs/csharp/language-reference/xmldoc/snippets/xmldoc/DocComments.cs

View workflow job for this annotation

GitHub Actions / snippets-build

This member is not allowed in an extension block
}
}
// </ExtensionExample>
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DocumentationFile>xmldoc.xml</DocumentationFile>
Expand Down
28 changes: 27 additions & 1 deletion docs/csharp/whats-new/csharp-15.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: What's new in C# 15
description: Get an overview of the new features in C# 15. C# 15 ships with .NET 11.
ms.date: 06/16/2026
ms.date: 07/08/2026
ms.topic: whats-new
ms.update-cycle: 365-days
ai-usage: ai-assisted
Expand All @@ -13,6 +13,7 @@ C# 15 includes the following new features. Try these features by using the lates
- [Collection expression arguments](#collection-expression-arguments)
- [Union types](#union-types)
- [Closed hierarchies](#closed-hierarchies)
- [Extension indexers](#extension-indexers)
- [Memory safety](#memory-safety)

C# 15 is the latest C# preview release. .NET 11 preview versions support C# 15. For more information, see [C# language versioning](../language-reference/configure-language-version.md).
Expand Down Expand Up @@ -108,6 +109,31 @@ The `closed` modifier is a contextual keyword. A `closed` class is implicitly `a

For more information, see the [closed modifier](../language-reference/keywords/closed.md) and [Closed hierarchy patterns](../language-reference/operators/patterns.md#closed-hierarchy-patterns) in the language reference, or the [feature specification](~/_csharplang/proposals/closed-hierarchies.md). You can copy the examples in this section, including the `ClosedAttribute` workaround, from the [keywords snippets project](https://github.com/dotnet/docs/blob/main/docs/csharp/language-reference/keywords/snippets/shared) in the `dotnet/docs` GitHub repository.

## Extension indexers

Starting with C# 15, you can declare *indexers* in an `extension` block. Extension indexers let you index into a receiver as though the indexer were declared on the receiver type. Because indexers are always instance members, an extension block that declares an indexer must provide a named receiver parameter.

The following example declares a get-only indexer on `IEnumerable<int>` that returns the element at a specified position:

```csharp
public static class SequenceIndexer
{
extension(IEnumerable<int> sequence)
{
public int this[int index] => sequence.ElementAt(index);
}
}
```

You index into the receiver as though the indexer were a member of the receiver type:

```csharp
IEnumerable<int> numbers = Enumerable.Range(1, 10);
int third = numbers[2];
```

For more information, see [Extension declaration](../language-reference/keywords/extension.md#extension-indexers) in the language reference or the [feature specification](~/_csharplang/proposals/extension-indexers.md).

## Memory safety

C# 15 begins a multirelease effort to redefine memory safety in the language. The goal is to tie the `unsafe` context to the operations that actually access unmanaged memory, rather than to the existence of pointer types. Most memory safety vulnerabilities come from these access operations, so the language makes them stand out for reviewers and auditors.
Expand Down
Loading