Skip to content

Commit fd386d1

Browse files
BillWagnergewarren
andauthored
Review delegate content in the C# programming guide (#44046)
* Move delegate samples * Fix the open issues - Add an example using an anonymouse method - Remove the references to C++ function pointers - Rewrite one heading * Proofread Refactor code, proofread and grammar check. Remove one example. It more or less repeated the previous full example. * Update docs/csharp/programming-guide/delegates/using-delegates.md Co-authored-by: Genevieve Warren <[email protected]> --------- Co-authored-by: Genevieve Warren <[email protected]>
1 parent ffb3a5c commit fd386d1

14 files changed

+497
-735
lines changed

docs/csharp/programming-guide/delegates/delegates-with-named-vs-anonymous-methods.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,27 @@
11
---
22
title: "Delegates with Named vs. Anonymous Methods"
3-
description: Learn about delegates with named vs. anonymous methods. See code examples and view additional available resources.
4-
ms.date: 11/22/2024
3+
description: Learn about delegates with named vs. anonymous methods. See code examples and view other available resources.
4+
ms.date: 12/20/2024
55
helpviewer_keywords:
66
- "delegates [C#], with named vs. anonymous methods"
77
- "methods [C#], in delegates"
8-
ms.assetid: 98fa8c61-66b6-4146-986c-3236c4045733
98
---
109
# Delegates with Named vs. Anonymous Methods (C# Programming Guide)
1110

1211
A [delegate](../../language-reference/builtin-types/reference-types.md) can be associated with a named method. When you instantiate a delegate by using a named method, the method is passed as a parameter, for example:
1312

14-
[!code-csharp[csProgGuideDelegates#1](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#1)]
13+
:::code language="csharp" source="./snippets/NamedAnonymousDelegates.cs" id="NamedDelegate":::
1514

16-
This is called using a named method. Delegates constructed with a named method can encapsulate either a [static](../../language-reference/keywords/static.md) method or an instance method. Named methods are the only way to instantiate a delegate in earlier versions of C#. However, in a situation where creating a new method is unwanted overhead, C# enables you to instantiate a delegate and immediately specify a code block that the delegate will process when it is called. The block can contain either a [lambda expression](../../language-reference/operators/lambda-expressions.md) or an [anonymous method](../../language-reference/operators/delegate-operator.md).
15+
The preceding example uses a named method. Delegates constructed with a named method can encapsulate either a [static](../../language-reference/keywords/static.md) method or an instance method. Named methods are the only way to instantiate a delegate in earlier versions of C#. C# enables you to instantiate a delegate and immediately specify a code block that the delegate processes when called. The block can contain either a [lambda expression](../../language-reference/operators/lambda-expressions.md) or an [anonymous method](../../language-reference/operators/delegate-operator.md), as shown in the following example:
1716

18-
The method that you pass as a delegate parameter must have the same signature as the delegate declaration. A delegate instance may encapsulate either static or instance method.
17+
:::code language="csharp" source="./snippets/NamedAnonymousDelegates.cs" id="SnippetAnonymousMethod":::
18+
19+
The method that you pass as a delegate parameter must have the same signature as the delegate declaration. A delegate instance can encapsulate either static or instance method.
1920

2021
> [!NOTE]
2122
> Although the delegate can use an [out](../../language-reference/keywords/method-parameters.md#out-parameter-modifier) parameter, we do not recommend its use with multicast event delegates because you cannot know which delegate will be called.
2223
23-
Method groups with a single overload have a *natural type*. This means the compiler can infer the return type and parameter types for the delegate type:
24+
Method groups with a single overload have a *natural type*. The compiler can infer the return type and parameter types for the delegate type:
2425

2526
```csharp
2627
var read = Console.Read; // Just one overload; Func<int> inferred
@@ -29,13 +30,13 @@ var write = Console.Write; // ERROR: Multiple overloads, can't choose
2930

3031
## Examples
3132

32-
The following is a simple example of declaring and using a delegate. Notice that both the delegate, `MultiplyCallback`, and the associated method, `MultiplyNumbers`, have the same signature
33+
The following example is a simple example of declaring and using a delegate. Notice that both the delegate, `MultiplyCallback`, and the associated method, `MultiplyNumbers`, have the same signature
3334

34-
[!code-csharp[csProgGuideDelegates#2](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#2)]
35+
:::code language="csharp" source="./snippets/NamedAnonymousDelegates.cs" id="DeclareAndUse":::
3536

3637
In the following example, one delegate is mapped to both static and instance methods and returns specific information from each.
3738

38-
[!code-csharp[csProgGuideDelegates#3](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#3)]
39+
:::code language="csharp" source="./snippets/NamedAnonymousDelegates.cs" id="AnotherSample":::
3940

4041
## See also
4142

docs/csharp/programming-guide/delegates/how-to-combine-delegates-multicast-delegates.md

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
11
---
22
title: "How to combine delegates (Multicast Delegates)"
3-
description: Learn how to combine delegates to create multicast delegates. See a code example and view additional available resources.
3+
description: Learn how to combine delegates to create multicast delegates. See a code example and view more available resources.
44
ms.topic: how-to
5-
ms.date: 07/20/2015
5+
ms.date: 12/20/2024
66
helpviewer_keywords:
77
- "delegates [C#], combining"
88
- "multicast delegates [C#]"
9-
ms.assetid: 4e689450-6d0c-46de-acfd-f961018ae5dd
109
---
1110
# How to combine delegates (Multicast Delegates) (C# Programming Guide)
1211

13-
This example demonstrates how to create multicast delegates. A useful property of [delegate](../../language-reference/builtin-types/reference-types.md) objects is that multiple objects can be assigned to one delegate instance by using the `+` operator. The multicast delegate contains a list of the assigned delegates. When the multicast delegate is called, it invokes the delegates in the list, in order. Only delegates of the same type can be combined.
14-
15-
The `-` operator can be used to remove a component delegate from a multicast delegate.
16-
17-
## Example
12+
This example demonstrates how to create multicast delegates. A useful property of [delegate](../../language-reference/builtin-types/reference-types.md) objects is that multiple objects can be assigned to one delegate instance by using the `+` operator. The multicast delegate contains a list of the assigned delegates. When the multicast delegate is called, it invokes the delegates in the list, in order. Only delegates of the same type can be combined. The `-` operator can be used to remove a component delegate from a multicast delegate.
13+
14+
:::code language="csharp" source="./snippets/MulticastExample.cs":::
1815

19-
[!code-csharp[csProgGuideDelegates#11](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#11)]
20-
2116
## See also
2217

2318
- <xref:System.MulticastDelegate>

docs/csharp/programming-guide/delegates/how-to-declare-instantiate-and-use-a-delegate.md

Lines changed: 25 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,41 @@
11
---
22
title: "How to declare, instantiate, and use a delegate"
3-
description: Learn how to declare, instantiate, and use a delegate. See examples that cover C# 1.0, 2.0, and 3.0 and later.
3+
description: Learn how to declare, instantiate, and use a delegate. This article provides several examples of declaring, instantiating, and invoking delegates.
44
ms.topic: how-to
5-
ms.date: 07/20/2015
5+
ms.date: 12/20/2024
66
helpviewer_keywords:
77
- "delegates [C#], declaring and instantiating"
8-
ms.assetid: 61c4895f-f785-48f8-8bfe-db73b411c4ae
98
---
109
# How to declare, instantiate, and use a Delegate (C# Programming Guide)
1110

1211
You can declare delegates using any of the following methods:
1312

1413
- Declare a delegate type and declare a method with a matching signature:
15-
16-
[!code-csharp[csProgGuideDelegates#13](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#13)]
17-
18-
[!code-csharp[csProgGuideDelegates#14](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#14)]
19-
14+
15+
:::code language="csharp" source="./snippets/HowToDeclareAndUse.cs" id="DeclareNamedDelegate":::
16+
17+
:::code language="csharp" source="./snippets/HowToDeclareAndUse.cs" id="CreateNamedInstance":::
18+
2019
- Assign a method group to a delegate type:
21-
22-
[!code-csharp[csProgGuideDelegates#32](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#32)]
23-
24-
- Declare an anonymous method:
25-
26-
[!code-csharp[csProgGuideDelegates#15](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#15)]
27-
20+
21+
:::code language="csharp" source="./snippets/HowToDeclareAndUse.cs" id="MethodGroup":::
22+
23+
- Declare an anonymous method
24+
25+
:::code language="csharp" source="./snippets/HowToDeclareAndUse.cs" id="AnonymousMethod":::
26+
2827
- Use a lambda expression:
29-
30-
[!code-csharp[csProgGuideDelegates#31](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#31)]
31-
32-
For more information, see [Lambda Expressions](../../language-reference/operators/lambda-expressions.md).
33-
34-
The following example illustrates declaring, instantiating, and using a delegate. The `BookDB` class encapsulates a bookstore database that maintains a database of books. It exposes a method, `ProcessPaperbackBooks`, which finds all paperback books in the database and calls a delegate for each one. The `delegate` type that is used is named `ProcessBookCallback`. The `Test` class uses this class to print the titles and average price of the paperback books.
35-
36-
The use of delegates promotes good separation of functionality between the bookstore database and the client code. The client code has no knowledge of how the books are stored or how the bookstore code finds paperback books. The bookstore code has no knowledge of what processing is performed on the paperback books after it finds them.
37-
38-
## Example
39-
40-
[!code-csharp[csProgGuideDelegates#12](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#12)]
41-
42-
## Robust Programming
43-
44-
- Declaring a delegate.
45-
46-
The following statement declares a new delegate type.
47-
48-
[!code-csharp[csProgGuideDelegates#16](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#16)]
49-
50-
Each delegate type describes the number and types of the arguments, and the type of the return value of methods that it can encapsulate. Whenever a new set of argument types or return value type is needed, a new delegate type must be declared.
51-
52-
- Instantiating a delegate.
53-
54-
After a delegate type has been declared, a delegate object must be created and associated with a particular method. In the previous example, you do this by passing the `PrintTitle` method to the `ProcessPaperbackBooks` method as in the following example:
55-
56-
[!code-csharp[csProgGuideDelegates#17](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#17)]
57-
58-
This creates a new delegate object associated with the [static](../../language-reference/keywords/static.md) method `Test.PrintTitle`. Similarly, the non-static method `AddBookToTotal` on the object `totaller` is passed as in the following example:
59-
60-
[!code-csharp[csProgGuideDelegates#18](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#18)]
61-
62-
In both cases a new delegate object is passed to the `ProcessPaperbackBooks` method.
63-
64-
After a delegate is created, the method it is associated with never changes; delegate objects are immutable.
65-
66-
- Calling a delegate.
67-
68-
After a delegate object is created, the delegate object is typically passed to other code that will call the delegate. A delegate object is called by using the name of the delegate object, followed by the parenthesized arguments to be passed to the delegate. Following is an example of a delegate call:
69-
70-
[!code-csharp[csProgGuideDelegates#19](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#19)]
71-
72-
A delegate can be either called synchronously, as in this example, or asynchronously by using `BeginInvoke` and `EndInvoke` methods.
73-
28+
29+
:::code language="csharp" source="./snippets/HowToDeclareAndUse.cs" id="LambdaExpression":::
30+
31+
For more information, see [Lambda Expressions](../../language-reference/operators/lambda-expressions.md).
32+
33+
The following example illustrates declaring, instantiating, and using a delegate. The `BookDB` class encapsulates a bookstore database that maintains a database of books. It exposes a method, `ProcessPaperbackBooks`, which finds all paperback books in the database and calls a delegate for each one. The `delegate` type is named `ProcessBookCallback`. The `Test` class uses this class to print the titles and average price of the paperback books.
34+
35+
The use of delegates promotes good separation of functionality between the bookstore database and the client code. The client code has no knowledge of how the books are stored or how the bookstore code finds paperback books. The bookstore code has no knowledge of what processing is performed on the paperback books after it finds them.
36+
37+
:::code language="csharp" source="./snippets/BookStore.cs":::
38+
7439
## See also
7540

7641
- [Events](../events/index.md)

docs/csharp/programming-guide/delegates/index.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
---
22
title: "Delegates"
33
description: A delegate in C# is a type that refers to methods with a parameter list and return type. Delegates are used to pass methods as arguments to other methods.
4-
ms.date: 02/02/2021
4+
ms.date: 12/20/2024
55
helpviewer_keywords:
66
- "C# language, delegates"
77
- "delegates [C#]"
8-
ms.assetid: 97de039b-c76b-4b9c-a27d-8c1e1c8d93da
98
---
109
# Delegates (C# Programming Guide)
1110

1211
A [delegate](../../language-reference/builtin-types/reference-types.md) is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method with a compatible signature and return type. You can invoke (or call) the method through the delegate instance.
1312

1413
Delegates are used to pass methods as arguments to other methods. Event handlers are nothing more than methods that are invoked through delegates. You create a custom method, and a class such as a windows control can call your method when a certain event occurs. The following example shows a delegate declaration:
1514

16-
[!code-csharp[csProgGuideDelegates#20](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#20)]
15+
:::code language="csharp" source="./snippets/Overview.cs" id="DelegateDeclaration":::
1716

1817
Any method from any accessible class or struct that matches the delegate type can be assigned to the delegate. The method can be either static or an instance method. This flexibility means you can programmatically change method calls, or plug new code into existing classes.
1918

@@ -28,7 +27,6 @@ This ability to refer to a method as a parameter makes delegates ideal for defin
2827

2928
Delegates have the following properties:
3029

31-
- Delegates are similar to C++ function pointers, but delegates are fully object-oriented, and unlike C++ pointers to member functions, delegates encapsulate both an object instance and a method.
3230
- Delegates allow methods to be passed as parameters.
3331
- Delegates can be used to define callback methods.
3432
- Delegates can be chained together; for example, multiple methods can be called on a single event.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
// A set of classes for handling a bookstore:
5+
namespace Bookstore;
6+
7+
// Describes a book in the book list:
8+
public record struct Book(string Title, string Author, decimal Price, bool Paperback);
9+
10+
// Declare a delegate type for processing a book:
11+
public delegate void ProcessBookCallback(Book book);
12+
13+
// Maintains a book database.
14+
public class BookDB
15+
{
16+
// List of all books in the database:
17+
List<Book> list = new();
18+
19+
// Add a book to the database:
20+
public void AddBook(string title, string author, decimal price, bool paperBack) =>
21+
list.Add(new Book(title, author, price, paperBack));
22+
23+
// Call a passed-in delegate on each paperback book to process it:
24+
public void ProcessPaperbackBooks(ProcessBookCallback processBook)
25+
{
26+
foreach (Book b in list)
27+
{
28+
if (b.Paperback)
29+
{
30+
// Calling the delegate:
31+
processBook(b);
32+
}
33+
}
34+
}
35+
}
36+
37+
// Using the Bookstore classes:
38+
39+
// Class to total and average prices of books:
40+
class PriceTotaller
41+
{
42+
private int countBooks = 0;
43+
private decimal priceBooks = 0.0m;
44+
45+
internal void AddBookToTotal(Book book)
46+
{
47+
countBooks += 1;
48+
priceBooks += book.Price;
49+
}
50+
51+
internal decimal AveragePrice() => priceBooks / countBooks;
52+
}
53+
54+
// Class to test the book database:
55+
class Test
56+
{
57+
// Print the title of the book.
58+
static void PrintTitle(Book b) => Console.WriteLine($" {b.Title}");
59+
60+
// Execution starts here.
61+
static void Main()
62+
{
63+
BookDB bookDB = new BookDB();
64+
65+
// Initialize the database with some books:
66+
AddBooks(bookDB);
67+
68+
// Print all the titles of paperbacks:
69+
Console.WriteLine("Paperback Book Titles:");
70+
71+
// Create a new delegate object associated with the static
72+
// method Test.PrintTitle:
73+
bookDB.ProcessPaperbackBooks(PrintTitle);
74+
75+
// Get the average price of a paperback by using
76+
// a PriceTotaller object:
77+
PriceTotaller totaller = new PriceTotaller();
78+
79+
// Create a new delegate object associated with the nonstatic
80+
// method AddBookToTotal on the object totaller:
81+
bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);
82+
83+
Console.WriteLine($"Average Paperback Book Price: ${totaller.AveragePrice():#.##}");
84+
}
85+
86+
// Initialize the book database with some test books:
87+
static void AddBooks(BookDB bookDB)
88+
{
89+
bookDB.AddBook("The C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true);
90+
bookDB.AddBook("The Unicode Standard 2.0", "The Unicode Consortium", 39.95m, true);
91+
bookDB.AddBook("The MS-DOS Encyclopedia", "Ray Duncan", 129.95m, false);
92+
bookDB.AddBook("Dogbert's Clues for the Clueless", "Scott Adams", 12.00m, true);
93+
}
94+
}
95+
/* Output:
96+
Paperback Book Titles:
97+
The C Programming Language
98+
The Unicode Standard 2.0
99+
Dogbert's Clues for the Clueless
100+
Average Paperback Book Price: $23.97
101+
*/
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net9.0</TargetFramework>
6+
<Nullable>enable</Nullable>
7+
<ImplicitUsings>true</ImplicitUsings>
8+
9+
<StartupObject>Bookstore.Test</StartupObject>
10+
</PropertyGroup>
11+
</Project>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace DelegateExamples;
8+
public class HowToDeclareAndUse
9+
{
10+
//<DeclareNamedDelegate>
11+
// Declare a delegate.
12+
delegate void NotifyCallback(string str);
13+
14+
// Declare a method with the same signature as the delegate.
15+
static void Notify(string name)
16+
{
17+
Console.WriteLine($"Notification received for: {name}");
18+
}
19+
//</DeclareNamedDelegate>
20+
21+
22+
public static void Examples()
23+
{
24+
//<CreateNamedInstance>
25+
// Create an instance of the delegate.
26+
NotifyCallback del1 = new NotifyCallback(Notify);
27+
//</CreateNamedInstance>
28+
29+
//<MethodGroup>
30+
NotifyCallback del2 = Notify;
31+
//</MethodGroup>
32+
33+
//<AnonymousMethod>
34+
// Instantiate NotifyCallback by using an anonymous method.
35+
NotifyCallback del3 = delegate (string name)
36+
{
37+
Console.WriteLine($"Notification received for: {name}");
38+
};
39+
//</AnonymousMethod>
40+
41+
//<LambdaExpression>
42+
// Instantiate NotifyCallback by using a lambda expression.
43+
NotifyCallback del4 = name => Console.WriteLine($"Notification received for: {name}");
44+
//</LambdaExpression>
45+
46+
}
47+
48+
}

0 commit comments

Comments
 (0)