Skip to content

Commit c0abcbd

Browse files
committed
Replace extension method with member
Where samples use `this` extension methods, except where explaining the `this` syntax, convert to the C# 14 extension member syntax,
1 parent e10eab7 commit c0abcbd

File tree

16 files changed

+43
-247
lines changed

16 files changed

+43
-247
lines changed

docs/csharp/language-reference/attributes/caller-information.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ The compiler injects the expression used for `condition` into the `message` argu
5858
Argument failed validation: <func is not null>
5959
```
6060

61-
This attribute enables you to write diagnostic utilities that provide more details. Developers can more quickly understand what changes are needed. You can also use the <xref:System.Runtime.CompilerServices.CallerArgumentExpressionAttribute> to determine what expression was used as the receiver for extension methods. The following method samples a sequence at regular intervals. If the sequence has fewer elements than the frequency, it reports an error:
61+
This attribute enables you to write diagnostic utilities that provide more details. Developers can more quickly understand what changes are needed. You can also use the <xref:System.Runtime.CompilerServices.CallerArgumentExpressionAttribute> to determine what expression was used as the receiver for extension members. The following method samples a sequence at regular intervals. If the sequence has fewer elements than the frequency, it reports an error:
6262

6363
:::code language="csharp" source="./snippets/CallerInformation.cs" id="ExtensionMethod":::
6464

docs/csharp/language-reference/attributes/snippets/CallerInformation.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,19 @@ public static void ValidateArgument(string parameterName, bool condition, [Calle
5656
public static class Extensions
5757
{
5858
// <ExtensionMethod>
59-
public static IEnumerable<T> Sample<T>(this IEnumerable<T> sequence, int frequency,
60-
[CallerArgumentExpression(nameof(sequence))] string? message = null)
59+
extension(IEnumerable<T> sequence)
6160
{
62-
if (sequence.Count() < frequency)
63-
throw new ArgumentException($"Expression doesn't have enough elements: {message}", nameof(sequence));
64-
int i = 0;
65-
foreach (T item in sequence)
61+
public static IEnumerable<T> Sample<T>(int frequency,
62+
[CallerArgumentExpression(nameof(sequence))] string? message = null)
6663
{
67-
if (i++ % frequency == 0)
68-
yield return item;
64+
if (sequence.Count() < frequency)
65+
throw new ArgumentException($"Expression doesn't have enough elements: {message}", nameof(sequence));
66+
int i = 0;
67+
foreach (T item in sequence)
68+
{
69+
if (i++ % frequency == 0)
70+
yield return item;
71+
}
6972
}
7073
}
7174
// </ExtensionMethod>

docs/csharp/language-reference/attributes/snippets/attributes.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
5-
<TargetFramework>net9.0</TargetFramework>
5+
<TargetFramework>net10.0</TargetFramework>
66
<Nullable>enable</Nullable>
77
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
88
<ImplicitUsings>enable</ImplicitUsings>

docs/csharp/language-reference/builtin-types/built-in-types.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "Built-in types"
33
description: "Learn C# built-in value and reference types"
4-
ms.date: 03/07/2025
4+
ms.date: 11/24/2025
55
helpviewer_keywords:
66
- "types [C#], built-in"
77
- "built-in C# types"
@@ -62,7 +62,7 @@ The C# language includes specialized rules for the <xref:System.Span`1?displayPr
6262
- From `System.ReadOnlySpan<E>` to `System.ReadOnlySpan<U>`, when `E` has a covariance conversion or an identity conversion to `U`
6363
- From `string` to `System.ReadOnlySpan<char>`
6464

65-
The compiler never ignores any user defined conversion where an applicable *implicit span conversion* exists. Implicit span conversions can be applied to the first argument of [extension methods](../../programming-guide/classes-and-structs/extension-methods.md), the parameter with the `this` modifier. Implicit span conversions aren't considered for method group conversions.
65+
The compiler never ignores any user defined conversion where an applicable *implicit span conversion* exists. Implicit span conversions can be applied to the first argument of [extension members](../../programming-guide/classes-and-structs/extension-methods.md), the parameter with the `this` modifier. Implicit span conversions aren't considered for method group conversions.
6666

6767
## See also
6868

docs/csharp/language-reference/builtin-types/enum.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: "Enumeration types"
33
description: "Learn about C# enumeration types that represent a choice or a combination of choices"
4-
ms.date: 12/13/2019
4+
ms.date: 11/24/2025
55
f1_keywords:
66
- "enum"
77
- "enum_CSharpKeyword"
@@ -10,7 +10,6 @@ helpviewer_keywords:
1010
- "enum type [C#]"
1111
- "enumeration type [C#]"
1212
- "bit flags [C#]"
13-
ms.assetid: bbeb9a0f-e9b3-41ab-b0a6-c41b1a08974c
1413
---
1514
# Enumeration types (C# reference)
1615

@@ -38,7 +37,7 @@ enum ErrorCode : ushort
3837
}
3938
```
4039

41-
You cannot define a method inside the definition of an enumeration type. To add functionality to an enumeration type, create an [extension method](../../programming-guide/classes-and-structs/extension-methods.md).
40+
You can't define a method inside the definition of an enumeration type. To add functionality to an enumeration type, create an [extension member](../../programming-guide/classes-and-structs/extension-methods.md).
4241

4342
The default value of an enumeration type `E` is the value produced by expression `(E)0`, even if zero doesn't have the corresponding enum member.
4443

@@ -48,9 +47,9 @@ C# allows implicit conversions from the literal value `0` to any enum type, and
4847

4948
:::code language="csharp" source="snippets/shared/EnumType.cs" id="SnippetZeroConversions":::
5049

51-
In the preceding example, both `port1` and `port2` are assigned the value `0`, but `GpioPort` has no member with that value. The <xref:System.Enum.IsDefined%2A?displayProperty=nameWithType> method confirms these are invalid enum values.
50+
In the preceding example, both `port1` and `port2` are assigned to the value `0`, but `GpioPort` has no member with that value. The <xref:System.Enum.IsDefined%2A?displayProperty=nameWithType> method confirms that 0 is an invalid enum value.
5251

53-
This implicit conversion exists because the 0 bit pattern is the default for all struct types, including all enum types. However, it can introduce bugs in your code. To avoid these issues:
52+
This implicit conversion exists because the 0-bit pattern is the default for all struct types, including all enum types. However, it can introduce bugs in your code. To avoid these issues:
5453

5554
- You should almost always define a member with value `0` in your enums.
5655
- Use <xref:System.Enum.IsDefined%2A?displayProperty=nameWithType> to validate enum values when converting from numeric types.
@@ -62,21 +61,21 @@ You use an enumeration type to represent a choice from a set of mutually exclusi
6261

6362
If you want an enumeration type to represent a combination of choices, define enum members for those choices such that an individual choice is a bit field. That is, the associated values of those enum members should be the powers of two. Then, you can use the [bitwise logical operators `|` or `&`](../operators/bitwise-and-shift-operators.md#enumeration-logical-operators) to combine choices or intersect combinations of choices, respectively. To indicate that an enumeration type declares bit fields, apply the [Flags](xref:System.FlagsAttribute) attribute to it. As the following example shows, you can also include some typical combinations in the definition of an enumeration type.
6463

65-
[!code-csharp[enum flags](snippets/shared/EnumType.cs#Flags)]
64+
:::code language="csharp" source="snippets/shared/EnumType.cs" id="SnippetFlags":::
6665

6766
For more information and examples, see the <xref:System.FlagsAttribute?displayProperty=nameWithType> API reference page and the [Non-exclusive members and the Flags attribute](../../../fundamentals/runtime-libraries/system-enum.md#non-exclusive-members-and-the-flags-attribute) section of the <xref:System.Enum?displayProperty=nameWithType> API reference page.
6867

6968
## The System.Enum type and enum constraint
7069

71-
The <xref:System.Enum?displayProperty=nameWithType> type is the abstract base class of all enumeration types. It provides a number of methods to get information about an enumeration type and its values. For more information and examples, see the <xref:System.Enum?displayProperty=nameWithType> API reference page.
70+
The <xref:System.Enum?displayProperty=nameWithType> type is the abstract base class of all enumeration types. It provides many methods to get information about an enumeration type and its values. For more information and examples, see the <xref:System.Enum?displayProperty=nameWithType> API reference page.
7271

7372
You can use `System.Enum` in a base class constraint (that is known as the [enum constraint](../../programming-guide/generics/constraints-on-type-parameters.md#enum-constraints)) to specify that a type parameter is an enumeration type. Any enumeration type also satisfies the `struct` constraint, which is used to specify that a type parameter is a non-nullable value type.
7473

7574
## Conversions
7675

7776
For any enumeration type, there exist explicit conversions between the enumeration type and its underlying integral type. If you [cast](../operators/type-testing-and-cast.md#cast-expression) an enum value to its underlying type, the result is the associated integral value of an enum member.
7877

79-
[!code-csharp[enum conversions](snippets/shared/EnumType.cs#Conversions)]
78+
:::code language="csharp" source="snippets/shared/EnumType.cs" id="SnippetConversions":::
8079

8180
Use the <xref:System.Enum.IsDefined%2A?displayProperty=nameWithType> method to determine whether an enumeration type contains an enum member with the certain associated value.
8281

docs/csharp/language-reference/compiler-messages/cs0122.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ ms.assetid: 5f639a66-c807-4166-b88a-93e5f272ceb7
1414

1515
The [access modifier](../keywords/index.md) for a class member prevents accessing the member. For more information, see [Access Modifiers](../../programming-guide/classes-and-structs/access-modifiers.md).
1616

17-
[Extension methods](../../programming-guide/classes-and-structs/extension-methods.md) cannot access private members of the type they are extending.
17+
[Extension members](../../programming-guide/classes-and-structs/extension-methods.md) cannot access private members of the type they are extending.
1818

1919
One cause of this (not shown in the sample below) can be omitting the **/out** compiler flag on the target of a friend assembly. For more information, see [Friend Assemblies](../../../standard/assembly/friend.md) and [**OutputAssembly** (C# Compiler Options)](../compiler-options/output.md#outputassembly).
2020

docs/csharp/language-reference/keywords/method-parameters.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ You can't use the previous parameter modifiers in the following kinds of methods
8080
- Async methods, which you define by using the [async](async.md) modifier.
8181
- Iterator methods, which include a [yield return](../statements/yield.md) or `yield break` statement.
8282

83-
[Extension methods](../../programming-guide/classes-and-structs/extension-methods.md) also have restrictions on the use of these argument keywords:
83+
[Extension members](../../programming-guide/classes-and-structs/extension-methods.md) also have restrictions on the use of these argument keywords:
8484

8585
- The `out` keyword can't be used on the first argument of an extension method.
8686
- The `ref` keyword can't be used on the first argument of an extension method when the argument isn't a `struct`, or a generic type not constrained to be a struct.

docs/csharp/language-reference/keywords/snippets/GenericWhereConstraints.cs

Lines changed: 0 additions & 204 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
using System.Collections.Generic;
44
using System.Text;
55

6-
using static Keywords.UnmanagedExtensions;
7-
86
namespace Keywords
97
{
108
// <Snippet1>
@@ -84,213 +82,11 @@ public void MyMethod<T>(T t) where T : IMyInterface { }
8482
// </Snippet8>
8583
}
8684

87-
// <Snippet9>
88-
public class Employee
89-
{
90-
public Employee(string s, int i) => (Name, ID) = (s, i);
91-
public string Name { get; set; }
92-
public int ID { get; set; }
93-
}
94-
95-
public class GenericList<T> where T : Employee
96-
{
97-
private class Node
98-
{
99-
public Node(T t) => (Next, Data) = (null, t);
100-
101-
public Node Next { get; set; }
102-
public T Data { get; set; }
103-
}
104-
105-
private Node head;
106-
107-
public void AddHead(T t)
108-
{
109-
Node n = new Node(t) { Next = head };
110-
head = n;
111-
}
112-
113-
public IEnumerator<T> GetEnumerator()
114-
{
115-
Node current = head;
116-
117-
while (current != null)
118-
{
119-
yield return current.Data;
120-
current = current.Next;
121-
}
122-
}
123-
124-
public T FindFirstOccurrence(string s)
125-
{
126-
Node current = head;
127-
T t = null;
128-
129-
while (current != null)
130-
{
131-
//The constraint enables access to the Name property.
132-
if (current.Data.Name == s)
133-
{
134-
t = current.Data;
135-
break;
136-
}
137-
else
138-
{
139-
current = current.Next;
140-
}
141-
}
142-
return t;
143-
}
144-
}
145-
// </Snippet9>
14685

14786
public interface IEmployee
14887
{
14988
}
15089

151-
// <Snippet10>
152-
class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
153-
{
154-
// ...
155-
}
156-
// </Snippet10>
157-
158-
// <Snippet12>
159-
class Base { }
160-
class Test<T, U>
161-
where U : struct
162-
where T : Base, new()
163-
{ }
164-
// </Snippet12>
165-
166-
namespace ListExample
167-
{
168-
// <Snippet13>
169-
public class List<T>
170-
{
171-
public void Add<U>(List<U> items) where U : T {/*...*/}
172-
}
173-
// </Snippet13>
174-
}
175-
176-
// <Snippet14>
177-
//Type parameter V is used as a type constraint.
178-
public class SampleClass<T, U, V> where T : V { }
179-
// </Snippet14>
180-
181-
public static class UnmanagedExtensions
182-
{
183-
// <Snippet15>
184-
unsafe public static byte[] ToByteArray<T>(this T argument) where T : unmanaged
185-
{
186-
var size = sizeof(T);
187-
var result = new Byte[size];
188-
Byte* p = (byte*)&argument;
189-
for (var i = 0; i < size; i++)
190-
result[i] = *p++;
191-
return result;
192-
}
193-
// </Snippet15>
194-
195-
// <Snippet16>
196-
public static TDelegate TypeSafeCombine<TDelegate>(this TDelegate source, TDelegate target)
197-
where TDelegate : System.Delegate
198-
=> Delegate.Combine(source, target) as TDelegate;
199-
// </Snippet16>
200-
201-
// <Snippet18>
202-
public static Dictionary<int, string> EnumNamedValues<T>() where T : System.Enum
203-
{
204-
var result = new Dictionary<int, string>();
205-
var values = Enum.GetValues(typeof(T));
206-
207-
foreach (int item in values)
208-
result.Add(item, Enum.GetName(typeof(T), item));
209-
return result;
210-
}
211-
// </Snippet18>
212-
}
213-
public static class GenericWhereConstraints
214-
{
215-
public static void Examples()
216-
{
217-
TestStringEquality();
218-
TestUnmanaged();
219-
TestDelegateCombination();
220-
TestEnumValues();
221-
}
222-
223-
// <Snippet11>
224-
public static void OpEqualsTest<T>(T s, T t) where T : class
225-
{
226-
System.Console.WriteLine(s == t);
227-
}
228-
private static void TestStringEquality()
229-
{
230-
string s1 = "target";
231-
System.Text.StringBuilder sb = new System.Text.StringBuilder("target");
232-
string s2 = sb.ToString();
233-
OpEqualsTest<string>(s1, s2);
234-
}
235-
// </Snippet11>
236-
237-
public struct Point3D
238-
{
239-
public double X { get; set; }
240-
public double Y { get; set; }
241-
public double Z { get; set; }
242-
}
243-
private static void TestUnmanaged()
244-
{
245-
var thing = new Point3D { X = 1, Y = 2, Z = 3 };
246-
247-
var storage = thing.ToByteArray();
248-
249-
for (int i = 0; i < storage.Length; i++)
250-
Console.Write($"{storage[i]:X2}, ");
251-
Console.WriteLine();
252-
}
253-
254-
private static void TestDelegateCombination()
255-
{
256-
// <Snippet17>
257-
Action first = () => Console.WriteLine("this");
258-
Action second = () => Console.WriteLine("that");
259-
260-
var combined = first.TypeSafeCombine(second);
261-
combined();
262-
263-
Func<bool> test = () => true;
264-
// Combine signature ensures combined delegates must
265-
// have the same type.
266-
//var badCombined = first.TypeSafeCombine(test);
267-
// </Snippet17>
268-
}
269-
270-
// <Snippet19>
271-
enum Rainbow
272-
{
273-
Red,
274-
Orange,
275-
Yellow,
276-
Green,
277-
Blue,
278-
Indigo,
279-
Violet
280-
}
281-
// </Snippet19>
282-
private static void TestEnumValues()
283-
{
284-
// <Snippet20>
285-
var map = EnumNamedValues<Rainbow>();
286-
287-
foreach (var pair in map)
288-
Console.WriteLine($"{pair.Key}:\t{pair.Value}");
289-
290-
// </Snippet20>
291-
}
292-
}
293-
29490
// <BaseClass>
29591
public abstract class B
29692
{

docs/csharp/language-reference/keywords/snippets/Program.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ class Program
88
{
99
static async Task Main(string[] args)
1010
{
11-
Console.WriteLine("================= Generic Where Constraints Examples ======================");
12-
GenericWhereConstraints.Examples();
1311
Console.WriteLine("================= readonly Keyword Examples ======================");
1412
ReadonlyKeywordExamples.Examples();
1513
Console.WriteLine("================= pass by value / reference Keyword Examples ======================");

docs/csharp/language-reference/keywords/this.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ helpviewer_keywords:
1313
The `this` keyword refers to the current instance of the class and is also used as a modifier of the first parameter of an extension method.
1414

1515
> [!NOTE]
16-
> This article discusses the use of `this` with class instances. For more information about its use in extension methods, see the [`extension`](./extension.md) keyword.
16+
> This article discusses the use of `this` to refer to the receiver instance in the current member. For more information about its use in extension methods, see the [`extension`](./extension.md) keyword.
1717
1818
The following are common uses of `this`:
1919

0 commit comments

Comments
 (0)