Skip to content

Commit 3ce2e97

Browse files
authored
Clarify extension method access (#42808)
* Clarify extension method declaration Extension methods can only be declared in top-level type. They can't be declared in nested types. * quick formatting fix * fix a snippet issue * one more time
1 parent 6673ac7 commit 3ce2e97

File tree

5 files changed

+86
-94
lines changed

5 files changed

+86
-94
lines changed

docs/csharp/programming-guide/classes-and-structs/how-to-implement-and-call-a-custom-extension-method.md

+21-30
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,33 @@
11
---
22
title: "How to implement and call a custom extension method"
33
description: Learn how to implement extension methods for any .NET type. Client code can use your methods by adding a reference to a DLL and adding a using directive.
4-
ms.date: 07/20/2015
4+
ms.date: 10/02/2024
55
helpviewer_keywords:
66
- "extension methods [C#], implementing and calling"
77
ms.topic: how-to
8-
ms.assetid: 7dab2a56-cf8e-4a47-a444-fe610a02772a
98
---
109
# How to implement and call a custom extension method (C# Programming Guide)
1110

12-
This topic shows how to implement your own extension methods for any .NET type. Client code can use your extension methods by adding a reference to the DLL that contains them, and adding a [using](../../language-reference/keywords/using-directive.md) directive that specifies the namespace in which the extension methods are defined.
13-
14-
## To define and call the extension method
15-
16-
1. Define a static [class](./static-classes-and-static-class-members.md) to contain the extension method.
17-
18-
The class must be visible to client code. For more information about accessibility rules, see [Access Modifiers](./access-modifiers.md).
19-
20-
2. Implement the extension method as a static method with at least the same visibility as the containing class.
21-
22-
3. The first parameter of the method specifies the type that the method operates on; it must be preceded with the [this](../../language-reference/keywords/this.md) modifier.
23-
24-
4. In the calling code, add a `using` directive to specify the [namespace](../../language-reference/keywords/namespace.md) that contains the extension method class.
25-
26-
5. Call the methods as if they were instance methods on the type.
27-
28-
Note that the first parameter is not specified by calling code because it represents the type on which the operator is being applied, and the compiler already knows the type of your object. You only have to provide arguments for parameters 2 through `n`.
29-
30-
## Example
31-
32-
The following example implements an extension method named `WordCount` in the `CustomExtensions.StringExtension` class. The method operates on the <xref:System.String> class, which is specified as the first method parameter. The `CustomExtensions` namespace is imported into the application namespace, and the method is called inside the `Main` method.
33-
34-
[!code-csharp[csProgGuideExtensionMethods#1](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideExtensionMethods/cs/extensionmethods.cs#1)]
35-
36-
## .NET Security
37-
38-
Extension methods present no specific security vulnerabilities. They can never be used to impersonate existing methods on a type, because all name collisions are resolved in favor of the instance or static method defined by the type itself. Extension methods cannot access any private data in the extended class.
39-
11+
This article shows how to implement your own extension methods for any .NET type. Client code can use your extension methods. Client projects must reference the assembly that contains them. Client projects must add a [using](../../language-reference/keywords/using-directive.md) directive that specifies the namespace in which the extension methods are defined.
12+
13+
To define and call the extension method:
14+
15+
1. Define a static [class](./static-classes-and-static-class-members.md) to contain the extension method. The class can't be nested inside another type and must be visible to client code. For more information about accessibility rules, see [Access Modifiers](./access-modifiers.md).
16+
1. Implement the extension method as a static method with at least the same visibility as the containing class.
17+
1. The first parameter of the method specifies the type that the method operates on; it must be preceded with the [this](../../language-reference/keywords/this.md) modifier.
18+
1. In the calling code, add a `using` directive to specify the [namespace](../../language-reference/keywords/namespace.md) that contains the extension method class.
19+
1. Call the methods as instance methods on the type.
20+
21+
> [!NOTE]
22+
>
23+
> The first parameter is not specified by calling code because it represents the type on which the operator is being applied, and the compiler already knows the type of your object. You only have to provide arguments for parameters 2 through `n`.
24+
25+
The following example implements an extension method named `WordCount` in the `CustomExtensions.StringExtension` class. The method operates on the <xref:System.String> class, which is specified as the first method parameter. The `CustomExtensions` namespace is imported into the application namespace, and the method is called inside the `Main` method.
26+
27+
:::code language="csharp" source="./snippets/how-to-implement-and-call-a-custom-extension-method/Program.cs" :::
28+
29+
Overload resolution prefers instance or static method defined by the type itself to extension methods. Extension methods can't access any private data in the extended class.
30+
4031
## See also
4132

4233
- [Extension Methods](./extension-methods.md)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using CustomExtensions;
2+
3+
string s = "The quick brown fox jumped over the lazy dog.";
4+
// Call the method as if it were an
5+
// instance method on the type. Note that the first
6+
// parameter is not specified by the calling code.
7+
int i = s.WordCount();
8+
System.Console.WriteLine("Word count of s is {0}", i);
9+
10+
11+
namespace CustomExtensions
12+
{
13+
// Extension methods must be defined in a static class.
14+
public static class StringExtension
15+
{
16+
// This is the extension method.
17+
// The first parameter takes the "this" modifier
18+
// and specifies the type for which the method is defined.
19+
public static int WordCount(this string str)
20+
{
21+
return str.Split(new char[] {' ', '.','?'}, StringSplitOptions.RemoveEmptyEntries).Length;
22+
}
23+
}
24+
}
25+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net9.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
</Project>

samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideExtensionMethods/cs/extensionmethods.cs

+29-63
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,4 @@
1-
//<Snippet1>
2-
namespace CustomExtensions
3-
{
4-
// Extension methods must be defined in a static class.
5-
public static class StringExtension
6-
{
7-
// This is the extension method.
8-
// The first parameter takes the "this" modifier
9-
// and specifies the type for which the method is defined.
10-
public static int WordCount(this string str)
11-
{
12-
return str.Split(new char[] {' ', '.','?'}, StringSplitOptions.RemoveEmptyEntries).Length;
13-
}
14-
}
15-
}
16-
namespace Extension_Methods_Simple
17-
{
18-
// Import the extension method namespace.
19-
using CustomExtensions;
20-
class Program
21-
{
22-
static void Main(string[] args)
23-
{
24-
string s = "The quick brown fox jumped over the lazy dog.";
25-
// Call the method as if it were an
26-
// instance method on the type. Note that the first
27-
// parameter is not specified by the calling code.
28-
int i = s.WordCount();
29-
System.Console.WriteLine("Word count of s is {0}", i);
30-
}
31-
}
32-
}
33-
//</Snippet1>
34-
35-
namespace Extension2
1+
namespace Extension2
362
{
373

384
//<snippet2>
@@ -42,40 +8,40 @@ namespace EnumExtension
428
{
439
// Define an extension method in a non-nested static class.
4410
public static class Extensions
45-
{
46-
public static Grades minPassing = Grades.D;
47-
public static bool Passing(this Grades grade)
4811
{
49-
return grade >= minPassing;
12+
public static Grades minPassing = Grades.D;
13+
public static bool Passing(this Grades grade)
14+
{
15+
return grade >= minPassing;
16+
}
5017
}
51-
}
5218

53-
public enum Grades { F = 0, D=1, C=2, B=3, A=4 };
54-
class Program
55-
{
56-
static void Main(string[] args)
19+
public enum Grades { F = 0, D=1, C=2, B=3, A=4 };
20+
class Program
5721
{
58-
Grades g1 = Grades.D;
59-
Grades g2 = Grades.F;
60-
Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
61-
Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");
62-
63-
Extensions.minPassing = Grades.C;
64-
Console.WriteLine("\r\nRaising the bar!\r\n");
65-
Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
66-
Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");
67-
}
68-
}
69-
}
70-
/* Output:
71-
First is a passing grade.
72-
Second is not a passing grade.
22+
static void Main(string[] args)
23+
{
24+
Grades g1 = Grades.D;
25+
Grades g2 = Grades.F;
26+
Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
27+
Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");
28+
29+
Extensions.minPassing = Grades.C;
30+
Console.WriteLine("\r\nRaising the bar!\r\n");
31+
Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
32+
Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");
33+
}
34+
/* Output:
35+
First is a passing grade.
36+
Second is not a passing grade.
7337
74-
Raising the bar!
38+
Raising the bar!
7539
76-
First is not a passing grade.
77-
Second is not a passing grade.
78-
*/
40+
First is not a passing grade.
41+
Second is not a passing grade.
42+
*/
43+
}
44+
}
7945
//</snippet2>
8046
} //namespace Extension2
8147

samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideExtensionMethods/cs/extensionmethods.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<Nullable>enable</Nullable>
77
<ImplicitUsings>enable</ImplicitUsings>
88
<AssemblyName>ExtensionMethods</AssemblyName>
9-
<StartupObject>Extension_Methods_Simple.Program</StartupObject>
9+
<StartupObject>Extension2.EnumExtension.Program</StartupObject>
1010
</PropertyGroup>
1111

1212
</Project>

0 commit comments

Comments
 (0)