From fd386d129c23d3c8eaa33de70edaac32276dc52c Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Sat, 21 Dec 2024 09:40:33 -0500 Subject: [PATCH] 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 <24882762+gewarren@users.noreply.github.com> --------- Co-authored-by: Genevieve Warren <24882762+gewarren@users.noreply.github.com> --- ...legates-with-named-vs-anonymous-methods.md | 21 +- ...o-combine-delegates-multicast-delegates.md | 15 +- ...-declare-instantiate-and-use-a-delegate.md | 85 +-- .../programming-guide/delegates/index.md | 6 +- .../delegates/snippets/BookStore.cs | 101 +++ .../snippets/DelegateExamples.csproj | 11 + .../delegates/snippets/HowToDeclareAndUse.cs | 48 ++ .../delegates/snippets/MulticastExample.cs | 67 ++ .../snippets/NamedAnonymousDelegates.cs | 110 ++++ .../delegates/snippets/Overview.cs | 8 + .../delegates/snippets/UsingDelegates.cs | 71 ++ .../delegates/using-delegates.md | 64 +- .../csProgGuideDelegates/CS/Delegates.cs | 611 ------------------ .../CS/csrefDelegates.csproj | 14 - 14 files changed, 497 insertions(+), 735 deletions(-) create mode 100644 docs/csharp/programming-guide/delegates/snippets/BookStore.cs create mode 100644 docs/csharp/programming-guide/delegates/snippets/DelegateExamples.csproj create mode 100644 docs/csharp/programming-guide/delegates/snippets/HowToDeclareAndUse.cs create mode 100644 docs/csharp/programming-guide/delegates/snippets/MulticastExample.cs create mode 100644 docs/csharp/programming-guide/delegates/snippets/NamedAnonymousDelegates.cs create mode 100644 docs/csharp/programming-guide/delegates/snippets/Overview.cs create mode 100644 docs/csharp/programming-guide/delegates/snippets/UsingDelegates.cs delete mode 100644 samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs delete mode 100644 samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/csrefDelegates.csproj diff --git a/docs/csharp/programming-guide/delegates/delegates-with-named-vs-anonymous-methods.md b/docs/csharp/programming-guide/delegates/delegates-with-named-vs-anonymous-methods.md index 2b226f93de07b..53ac1bc5add6e 100644 --- a/docs/csharp/programming-guide/delegates/delegates-with-named-vs-anonymous-methods.md +++ b/docs/csharp/programming-guide/delegates/delegates-with-named-vs-anonymous-methods.md @@ -1,26 +1,27 @@ --- title: "Delegates with Named vs. Anonymous Methods" -description: Learn about delegates with named vs. anonymous methods. See code examples and view additional available resources. -ms.date: 11/22/2024 +description: Learn about delegates with named vs. anonymous methods. See code examples and view other available resources. +ms.date: 12/20/2024 helpviewer_keywords: - "delegates [C#], with named vs. anonymous methods" - "methods [C#], in delegates" -ms.assetid: 98fa8c61-66b6-4146-986c-3236c4045733 --- # Delegates with Named vs. Anonymous Methods (C# Programming Guide) 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: -[!code-csharp[csProgGuideDelegates#1](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#1)] +:::code language="csharp" source="./snippets/NamedAnonymousDelegates.cs" id="NamedDelegate"::: -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). +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: -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. +:::code language="csharp" source="./snippets/NamedAnonymousDelegates.cs" id="SnippetAnonymousMethod"::: + +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. > [!NOTE] > 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. -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: +Method groups with a single overload have a *natural type*. The compiler can infer the return type and parameter types for the delegate type: ```csharp var read = Console.Read; // Just one overload; Func inferred @@ -29,13 +30,13 @@ var write = Console.Write; // ERROR: Multiple overloads, can't choose ## Examples -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 +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 -[!code-csharp[csProgGuideDelegates#2](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#2)] +:::code language="csharp" source="./snippets/NamedAnonymousDelegates.cs" id="DeclareAndUse"::: In the following example, one delegate is mapped to both static and instance methods and returns specific information from each. -[!code-csharp[csProgGuideDelegates#3](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#3)] +:::code language="csharp" source="./snippets/NamedAnonymousDelegates.cs" id="AnotherSample"::: ## See also diff --git a/docs/csharp/programming-guide/delegates/how-to-combine-delegates-multicast-delegates.md b/docs/csharp/programming-guide/delegates/how-to-combine-delegates-multicast-delegates.md index 432803f906def..8faf0d3ddb3af 100644 --- a/docs/csharp/programming-guide/delegates/how-to-combine-delegates-multicast-delegates.md +++ b/docs/csharp/programming-guide/delegates/how-to-combine-delegates-multicast-delegates.md @@ -1,23 +1,18 @@ --- title: "How to combine delegates (Multicast Delegates)" -description: Learn how to combine delegates to create multicast delegates. See a code example and view additional available resources. +description: Learn how to combine delegates to create multicast delegates. See a code example and view more available resources. ms.topic: how-to -ms.date: 07/20/2015 +ms.date: 12/20/2024 helpviewer_keywords: - "delegates [C#], combining" - "multicast delegates [C#]" -ms.assetid: 4e689450-6d0c-46de-acfd-f961018ae5dd --- # How to combine delegates (Multicast Delegates) (C# Programming Guide) -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. - -## Example +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. + +:::code language="csharp" source="./snippets/MulticastExample.cs"::: - [!code-csharp[csProgGuideDelegates#11](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#11)] - ## See also - diff --git a/docs/csharp/programming-guide/delegates/how-to-declare-instantiate-and-use-a-delegate.md b/docs/csharp/programming-guide/delegates/how-to-declare-instantiate-and-use-a-delegate.md index f03145567d163..7fb722dae8b5c 100644 --- a/docs/csharp/programming-guide/delegates/how-to-declare-instantiate-and-use-a-delegate.md +++ b/docs/csharp/programming-guide/delegates/how-to-declare-instantiate-and-use-a-delegate.md @@ -1,76 +1,41 @@ --- title: "How to declare, instantiate, and use a delegate" -description: Learn how to declare, instantiate, and use a delegate. See examples that cover C# 1.0, 2.0, and 3.0 and later. +description: Learn how to declare, instantiate, and use a delegate. This article provides several examples of declaring, instantiating, and invoking delegates. ms.topic: how-to -ms.date: 07/20/2015 +ms.date: 12/20/2024 helpviewer_keywords: - "delegates [C#], declaring and instantiating" -ms.assetid: 61c4895f-f785-48f8-8bfe-db73b411c4ae --- # How to declare, instantiate, and use a Delegate (C# Programming Guide) You can declare delegates using any of the following methods: - Declare a delegate type and declare a method with a matching signature: - - [!code-csharp[csProgGuideDelegates#13](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#13)] - - [!code-csharp[csProgGuideDelegates#14](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#14)] - + + :::code language="csharp" source="./snippets/HowToDeclareAndUse.cs" id="DeclareNamedDelegate"::: + + :::code language="csharp" source="./snippets/HowToDeclareAndUse.cs" id="CreateNamedInstance"::: + - Assign a method group to a delegate type: - - [!code-csharp[csProgGuideDelegates#32](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#32)] - -- Declare an anonymous method: - - [!code-csharp[csProgGuideDelegates#15](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#15)] - + + :::code language="csharp" source="./snippets/HowToDeclareAndUse.cs" id="MethodGroup"::: + +- Declare an anonymous method + + :::code language="csharp" source="./snippets/HowToDeclareAndUse.cs" id="AnonymousMethod"::: + - Use a lambda expression: - - [!code-csharp[csProgGuideDelegates#31](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#31)] - - For more information, see [Lambda Expressions](../../language-reference/operators/lambda-expressions.md). - - 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. - - 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. - -## Example - - [!code-csharp[csProgGuideDelegates#12](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#12)] - -## Robust Programming - -- Declaring a delegate. - - The following statement declares a new delegate type. - - [!code-csharp[csProgGuideDelegates#16](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#16)] - - 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. - -- Instantiating a delegate. - - 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: - - [!code-csharp[csProgGuideDelegates#17](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#17)] - - 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: - - [!code-csharp[csProgGuideDelegates#18](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#18)] - - In both cases a new delegate object is passed to the `ProcessPaperbackBooks` method. - - After a delegate is created, the method it is associated with never changes; delegate objects are immutable. - -- Calling a delegate. - - 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: - - [!code-csharp[csProgGuideDelegates#19](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#19)] - - A delegate can be either called synchronously, as in this example, or asynchronously by using `BeginInvoke` and `EndInvoke` methods. - + + :::code language="csharp" source="./snippets/HowToDeclareAndUse.cs" id="LambdaExpression"::: + +For more information, see [Lambda Expressions](../../language-reference/operators/lambda-expressions.md). + +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. + +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. + +:::code language="csharp" source="./snippets/BookStore.cs"::: + ## See also - [Events](../events/index.md) diff --git a/docs/csharp/programming-guide/delegates/index.md b/docs/csharp/programming-guide/delegates/index.md index a975e98ad973a..f875bfe0d3fec 100644 --- a/docs/csharp/programming-guide/delegates/index.md +++ b/docs/csharp/programming-guide/delegates/index.md @@ -1,11 +1,10 @@ --- title: "Delegates" 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. -ms.date: 02/02/2021 +ms.date: 12/20/2024 helpviewer_keywords: - "C# language, delegates" - "delegates [C#]" -ms.assetid: 97de039b-c76b-4b9c-a27d-8c1e1c8d93da --- # Delegates (C# Programming Guide) @@ -13,7 +12,7 @@ A [delegate](../../language-reference/builtin-types/reference-types.md) is a typ 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: -[!code-csharp[csProgGuideDelegates#20](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#20)] +:::code language="csharp" source="./snippets/Overview.cs" id="DelegateDeclaration"::: 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. @@ -28,7 +27,6 @@ This ability to refer to a method as a parameter makes delegates ideal for defin Delegates have the following properties: -- 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. - Delegates allow methods to be passed as parameters. - Delegates can be used to define callback methods. - Delegates can be chained together; for example, multiple methods can be called on a single event. diff --git a/docs/csharp/programming-guide/delegates/snippets/BookStore.cs b/docs/csharp/programming-guide/delegates/snippets/BookStore.cs new file mode 100644 index 0000000000000..3bf7150244e7b --- /dev/null +++ b/docs/csharp/programming-guide/delegates/snippets/BookStore.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; + +// A set of classes for handling a bookstore: +namespace Bookstore; + +// Describes a book in the book list: +public record struct Book(string Title, string Author, decimal Price, bool Paperback); + +// Declare a delegate type for processing a book: +public delegate void ProcessBookCallback(Book book); + +// Maintains a book database. +public class BookDB +{ + // List of all books in the database: + List list = new(); + + // Add a book to the database: + public void AddBook(string title, string author, decimal price, bool paperBack) => + list.Add(new Book(title, author, price, paperBack)); + + // Call a passed-in delegate on each paperback book to process it: + public void ProcessPaperbackBooks(ProcessBookCallback processBook) + { + foreach (Book b in list) + { + if (b.Paperback) + { + // Calling the delegate: + processBook(b); + } + } + } +} + +// Using the Bookstore classes: + +// Class to total and average prices of books: +class PriceTotaller +{ + private int countBooks = 0; + private decimal priceBooks = 0.0m; + + internal void AddBookToTotal(Book book) + { + countBooks += 1; + priceBooks += book.Price; + } + + internal decimal AveragePrice() => priceBooks / countBooks; +} + +// Class to test the book database: +class Test +{ + // Print the title of the book. + static void PrintTitle(Book b) => Console.WriteLine($" {b.Title}"); + + // Execution starts here. + static void Main() + { + BookDB bookDB = new BookDB(); + + // Initialize the database with some books: + AddBooks(bookDB); + + // Print all the titles of paperbacks: + Console.WriteLine("Paperback Book Titles:"); + + // Create a new delegate object associated with the static + // method Test.PrintTitle: + bookDB.ProcessPaperbackBooks(PrintTitle); + + // Get the average price of a paperback by using + // a PriceTotaller object: + PriceTotaller totaller = new PriceTotaller(); + + // Create a new delegate object associated with the nonstatic + // method AddBookToTotal on the object totaller: + bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal); + + Console.WriteLine($"Average Paperback Book Price: ${totaller.AveragePrice():#.##}"); + } + + // Initialize the book database with some test books: + static void AddBooks(BookDB bookDB) + { + bookDB.AddBook("The C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true); + bookDB.AddBook("The Unicode Standard 2.0", "The Unicode Consortium", 39.95m, true); + bookDB.AddBook("The MS-DOS Encyclopedia", "Ray Duncan", 129.95m, false); + bookDB.AddBook("Dogbert's Clues for the Clueless", "Scott Adams", 12.00m, true); + } +} +/* Output: +Paperback Book Titles: + The C Programming Language + The Unicode Standard 2.0 + Dogbert's Clues for the Clueless +Average Paperback Book Price: $23.97 +*/ diff --git a/docs/csharp/programming-guide/delegates/snippets/DelegateExamples.csproj b/docs/csharp/programming-guide/delegates/snippets/DelegateExamples.csproj new file mode 100644 index 0000000000000..9987434fbeff0 --- /dev/null +++ b/docs/csharp/programming-guide/delegates/snippets/DelegateExamples.csproj @@ -0,0 +1,11 @@ + + + + Exe + net9.0 + enable + true + + Bookstore.Test + + diff --git a/docs/csharp/programming-guide/delegates/snippets/HowToDeclareAndUse.cs b/docs/csharp/programming-guide/delegates/snippets/HowToDeclareAndUse.cs new file mode 100644 index 0000000000000..de09749d049bb --- /dev/null +++ b/docs/csharp/programming-guide/delegates/snippets/HowToDeclareAndUse.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DelegateExamples; +public class HowToDeclareAndUse +{ + // + // Declare a delegate. + delegate void NotifyCallback(string str); + + // Declare a method with the same signature as the delegate. + static void Notify(string name) + { + Console.WriteLine($"Notification received for: {name}"); + } + // + + + public static void Examples() + { + // + // Create an instance of the delegate. + NotifyCallback del1 = new NotifyCallback(Notify); + // + + // + NotifyCallback del2 = Notify; + // + + // + // Instantiate NotifyCallback by using an anonymous method. + NotifyCallback del3 = delegate (string name) + { + Console.WriteLine($"Notification received for: {name}"); + }; + // + + // + // Instantiate NotifyCallback by using a lambda expression. + NotifyCallback del4 = name => Console.WriteLine($"Notification received for: {name}"); + // + + } + +} diff --git a/docs/csharp/programming-guide/delegates/snippets/MulticastExample.cs b/docs/csharp/programming-guide/delegates/snippets/MulticastExample.cs new file mode 100644 index 0000000000000..2c6a61a38416e --- /dev/null +++ b/docs/csharp/programming-guide/delegates/snippets/MulticastExample.cs @@ -0,0 +1,67 @@ +using System; + + +namespace DelegateExamples; + +// Define a custom delegate that has a string parameter and returns void. +delegate void CustomCallback(string s); + +class TestClass +{ + // Define two methods that have the same signature as CustomCallback. + static void Hello(string s) + { + Console.WriteLine($" Hello, {s}!"); + } + + static void Goodbye(string s) + { + Console.WriteLine($" Goodbye, {s}!"); + } + + static void Main() + { + // Declare instances of the custom delegate. + CustomCallback hiDel, byeDel, multiDel, multiMinusHiDel; + + // In this example, you can omit the custom delegate if you + // want to and use Action instead. + //Action hiDel, byeDel, multiDel, multiMinusHiDel; + + // Initialize the delegate object hiDel that references the + // method Hello. + hiDel = Hello; + + // Initialize the delegate object byeDel that references the + // method Goodbye. + byeDel = Goodbye; + + // The two delegates, hiDel and byeDel, are combined to + // form multiDel. + multiDel = hiDel + byeDel; + + // Remove hiDel from the multicast delegate, leaving byeDel, + // which calls only the method Goodbye. + multiMinusHiDel = (multiDel - hiDel)!; + + Console.WriteLine("Invoking delegate hiDel:"); + hiDel("A"); + Console.WriteLine("Invoking delegate byeDel:"); + byeDel("B"); + Console.WriteLine("Invoking delegate multiDel:"); + multiDel("C"); + Console.WriteLine("Invoking delegate multiMinusHiDel:"); + multiMinusHiDel("D"); + } +} +/* Output: +Invoking delegate hiDel: + Hello, A! +Invoking delegate byeDel: + Goodbye, B! +Invoking delegate multiDel: + Hello, C! + Goodbye, C! +Invoking delegate multiMinusHiDel: + Goodbye, D! +*/ diff --git a/docs/csharp/programming-guide/delegates/snippets/NamedAnonymousDelegates.cs b/docs/csharp/programming-guide/delegates/snippets/NamedAnonymousDelegates.cs new file mode 100644 index 0000000000000..6ba386c0ae8b6 --- /dev/null +++ b/docs/csharp/programming-guide/delegates/snippets/NamedAnonymousDelegates.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DelegateExamples; +class NamedDelegate +{ + static NamedDelegate obj = new NamedDelegate(); + + // + // Declare a delegate. + delegate void WorkCallback(int x); + + // Define a named method. + void DoWork(int k) { /* ... */ } + + // Instantiate the delegate using the method as a parameter. + WorkCallback d = obj.DoWork; + // +} + +class AnonymousDelegate +{ + static AnonymousDelegate obj = new AnonymousDelegate(); + + // + // Declare a delegate. + delegate void WorkCallback(int x); + + // Instantiate the delegate using an anonymous method. + WorkCallback d = (int k) => { /* ... */ }; + // +} + +// +// Declare a delegate +delegate void MultiplyCallback(int i, double j); + +class MathClass +{ + static void Main() + { + MathClass m = new MathClass(); + + // Delegate instantiation using "MultiplyNumbers" + MultiplyCallback d = m.MultiplyNumbers; + + // Invoke the delegate object. + Console.WriteLine("Invoking the delegate using 'MultiplyNumbers':"); + for (int i = 1; i <= 5; i++) + { + d(i, 2); + } + + // Keep the console window open in debug mode. + Console.WriteLine("Press any key to exit."); + Console.ReadKey(); + } + + // Declare the associated method. + void MultiplyNumbers(int m, double n) + { + Console.Write(m * n + " "); + } +} +/* Output: + Invoking the delegate using 'MultiplyNumbers': + 2 4 6 8 10 +*/ +// + +// +// Declare a delegate +delegate void Callback(); + +class SampleClass +{ + public void InstanceMethod() + { + Console.WriteLine("A message from the instance method."); + } + + static public void StaticMethod() + { + Console.WriteLine("A message from the static method."); + } +} + +class TestSampleClass +{ + static void Main() + { + var sc = new SampleClass(); + + // Map the delegate to the instance method: + Callback d = sc.InstanceMethod; + d(); + + // Map to the static method: + d = SampleClass.StaticMethod; + d(); + } +} +/* Output: + A message from the instance method. + A message from the static method. +*/ +// diff --git a/docs/csharp/programming-guide/delegates/snippets/Overview.cs b/docs/csharp/programming-guide/delegates/snippets/Overview.cs new file mode 100644 index 0000000000000..d2bfdd7397e79 --- /dev/null +++ b/docs/csharp/programming-guide/delegates/snippets/Overview.cs @@ -0,0 +1,8 @@ +namespace DelegateExamples; + +public class OverViewExamples +{ + // + public delegate int PerformCalculation(int x, int y); + // +} diff --git a/docs/csharp/programming-guide/delegates/snippets/UsingDelegates.cs b/docs/csharp/programming-guide/delegates/snippets/UsingDelegates.cs new file mode 100644 index 0000000000000..6cfd47022f87a --- /dev/null +++ b/docs/csharp/programming-guide/delegates/snippets/UsingDelegates.cs @@ -0,0 +1,71 @@ +using System; + +namespace DelegateExamples; +public class UsingDelegates +{ + // + public delegate void Callback(string message); + // + + // + // Create a method for a delegate. + public static void DelegateMethod(string message) + { + Console.WriteLine(message); + } + // + + public static void Examples() + { + // + // Instantiate the delegate. + Callback handler = DelegateMethod; + + // Call the delegate. + handler("Hello World"); + // + + // + MethodWithCallback(1, 2, handler); + // + + // + var obj = new MethodClass(); + Callback d1 = obj.Method1; + Callback d2 = obj.Method2; + Callback d3 = DelegateMethod; + + //Both types of assignment are valid. + Callback allMethodsDelegate = d1 + d2; + allMethodsDelegate += d3; + // + + // + //remove Method1 + allMethodsDelegate -= d1; + + // copy AllMethodsDelegate while removing d2 + Callback oneMethodDelegate = (allMethodsDelegate - d2)!; + // + + // + int invocationCount = d1.GetInvocationList().GetLength(0); + // + } + + // + public static void MethodWithCallback(int param1, int param2, Callback callback) + { + callback("The number is: " + (param1 + param2).ToString()); + } + // +} + +// +public class MethodClass +{ + public void Method1(string message) { } + public void Method2(string message) { } +} +// + diff --git a/docs/csharp/programming-guide/delegates/using-delegates.md b/docs/csharp/programming-guide/delegates/using-delegates.md index 2478c04b06d9c..4384e3aa7ff15 100644 --- a/docs/csharp/programming-guide/delegates/using-delegates.md +++ b/docs/csharp/programming-guide/delegates/using-delegates.md @@ -1,66 +1,78 @@ --- title: "Using Delegates" description: Learn how to use delegates. Delegates are an object-oriented, type safe, and secure type that safely encapsulates a method. -ms.date: 07/31/2023 +ms.date: 12/20/2024 helpviewer_keywords: - "delegates [C#], how to use" -ms.assetid: 99a2fc27-a32e-4a34-921c-e65497520eec --- # Using Delegates (C# Programming Guide) -A [delegate](../../language-reference/builtin-types/reference-types.md) is a type that safely encapsulates a method, similar to a function pointer in C and C++. Unlike C function pointers, delegates are object-oriented, type safe, and secure. The type of a delegate is defined by the name of the delegate. The following example declares a delegate named `Callback` that can encapsulate a method that takes a [string](../../language-reference/builtin-types/reference-types.md) as an argument and returns [void](../../language-reference/builtin-types/void.md): +A [delegate](../../language-reference/builtin-types/reference-types.md) is a type that safely encapsulates a method, similar to a function pointer in C and C++. Unlike C function pointers, delegates are object-oriented, type safe, and secure. The following example declares a delegate named `Callback` that can encapsulate a method that takes a [string](../../language-reference/builtin-types/reference-types.md) as an argument and returns [void](../../language-reference/builtin-types/void.md): -[!code-csharp[csProgGuideDelegates#21](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#21)] +:::code language="csharp" source="./snippets/UsingDelegates.cs" id="DeclareDelegate"::: -A delegate object is normally constructed by providing the name of the method the delegate will wrap, or with a [lambda expression](../../language-reference/operators/lambda-expressions.md). Once a delegate is instantiated in this manner it can be invoked. Invoking a delegate calls the method attached to the delegate instance. The parameters passed to the delegate by the caller are passed to the method, and the return value, if any, from the method is returned to the caller by the delegate. For example: +A delegate object is normally constructed by providing the name of the method the delegate wraps, or with a [lambda expression](../../language-reference/operators/lambda-expressions.md). A delegate can be invoked once instantiated in this manner. Invoking a delegate calls the method attached to the delegate instance. The parameters passed to the delegate by the caller are passed to the method. The delegate returns the return value, if any, from the method. For example: -[!code-csharp[csProgGuideDelegates#22](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#22)] +:::code language="csharp" source="./snippets/UsingDelegates.cs" id="DelegateMethod"::: -[!code-csharp[csProgGuideDelegates#23](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#23)] +:::code language="csharp" source="./snippets/UsingDelegates.cs" id="UseDelegate"::: -Delegate types are derived from the class in .NET. Delegate types are [sealed](../../language-reference/keywords/sealed.md)—they cannot be derived from— and it is not possible to derive custom classes from . Because the instantiated delegate is an object, it can be passed as an argument, or assigned to a property. This allows a method to accept a delegate as a parameter, and call the delegate at some later time. This is known as an asynchronous callback, and is a common method of notifying a caller when a long process has completed. When a delegate is used in this fashion, the code using the delegate does not need any knowledge of the implementation of the method being used. The functionality is similar to the encapsulation interfaces provide. +Delegate types are derived from the class in .NET. Delegate types are [sealed](../../language-reference/keywords/sealed.md), they can't be derived from, and it isn't possible to derive custom classes from . Because the instantiated delegate is an object, it can be passed as an argument, or assigned to a property. A method can accept a delegate as a parameter, and call the delegate at some later time. This is known as an asynchronous callback, and is a common method of notifying a caller when a long process completes. When a delegate is used in this fashion, the code using the delegate doesn't need any knowledge of the implementation of the method being used. The functionality is similar to the encapsulation interfaces provide. Another common use of callbacks is defining a custom comparison method and passing that delegate to a sort method. It allows the caller's code to become part of the sort algorithm. The following example method uses the `Del` type as a parameter: -[!code-csharp[csProgGuideDelegates#24](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#24)] +:::code language="csharp" source="./snippets/UsingDelegates.cs" id="DelegateParameter"::: -You can then pass the delegate created above to that method: +You can then pass the delegate created in the preceding example to that method: -[!code-csharp[csProgGuideDelegates#25](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#25)] +:::code language="csharp" source="./snippets/UsingDelegates.cs" id="DelegateArgument"::: -and receive the following output to the console: +And receive the following output to the console: ```console The number is: 3 ``` -Using the delegate as an abstraction, `MethodWithCallback` does not need to call the console directly—it does not have to be designed with a console in mind. What `MethodWithCallback` does is simply prepare a string and pass the string to another method. This is especially powerful since a delegated method can use any number of parameters. +`MethodWithCallback` doesn't need to call the console directly—it doesn't have to be designed with a console in mind. What `MethodWithCallback` does is prepare a string and pass the string to another method. A delegated method can use any number of parameters. -When a delegate is constructed to wrap an instance method, the delegate references both the instance and the method. A delegate has no knowledge of the instance type aside from the method it wraps, so a delegate can refer to any type of object as long as there is a method on that object that matches the delegate signature. When a delegate is constructed to wrap a static method, it only references the method. Consider the following declarations: +When a delegate is constructed to wrap an instance method, the delegate references both the instance and the method. A delegate has no knowledge of the instance type aside from the method it wraps. A delegate can refer to any type of object as long as there's a method on that object that matches the delegate signature. When a delegate is constructed to wrap a static method, it only references the method. Consider the following declarations: -[!code-csharp[csProgGuideDelegates#26](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#26)] +:::code language="csharp" source="./snippets/UsingDelegates.cs" id="InstanceMethods"::: -Along with the static `DelegateMethod` shown previously, we now have three methods that can be wrapped by a `Del` instance. +Along with the static `DelegateMethod` shown previously, we now have three methods that you can wrap in a `Del` instance. -A delegate can call more than one method when invoked. This is referred to as multicasting. To add an extra method to the delegate's list of methods—the invocation list—simply requires adding two delegates using the addition or addition assignment operators ('+' or '+='). For example: +A delegate can call more than one method when invoked, referred to as multicasting. To add an extra method to the delegate's list of methods—the invocation list—simply requires adding two delegates using the addition or addition assignment operators ('+' or '+='). For example: -[!code-csharp[csProgGuideDelegates#27](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#27)] +:::code language="csharp" source="./snippets/UsingDelegates.cs" id="UseInstanceDelegates"::: -At this point `allMethodsDelegate` contains three methods in its invocation list—`Method1`, `Method2`, and `DelegateMethod`. The original three delegates, `d1`, `d2`, and `d3`, remain unchanged. When `allMethodsDelegate` is invoked, all three methods are called in order. If the delegate uses reference parameters, the reference is passed sequentially to each of the three methods in turn, and any changes by one method are visible to the next method. When any of the methods throws an exception that is not caught within the method, that exception is passed to the caller of the delegate and no subsequent methods in the invocation list are called. If the delegate has a return value and/or out parameters, it returns the return value and parameters of the last method invoked. To remove a method from the invocation list, use the [subtraction or subtraction assignment operators](../../language-reference/operators/subtraction-operator.md) (`-` or `-=`). For example: +The `allMethodsDelegate` contains three methods in its invocation list—`Method1`, `Method2`, and `DelegateMethod`. The original three delegates, `d1`, `d2`, and `d3`, remain unchanged. When `allMethodsDelegate` is invoked, all three methods are called in order. If the delegate uses reference parameters, the reference is passed sequentially to each of the three methods in turn, and any changes by one method are visible to the next method. When any of the methods throws an exception that isn't caught within the method, that exception is passed to the caller of the delegate. No subsequent methods in the invocation list are called. If the delegate has a return value and/or out parameters, it returns the return value and parameters of the last method invoked. To remove a method from the invocation list, use the [subtraction or subtraction assignment operators](../../language-reference/operators/subtraction-operator.md) (`-` or `-=`). For example: -[!code-csharp[csProgGuideDelegates#28](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#28)] +:::code language="csharp" source="./snippets/UsingDelegates.cs" id="RemoveAddDelegates"::: -Because delegate types are derived from `System.Delegate`, the methods and properties defined by that class can be called on the delegate. For example, to find the number of methods in a delegate's invocation list, you may write: +Because delegate types are derived from `System.Delegate`, the methods and properties defined by that class can be called on the delegate. For example, to find the number of methods in a delegate's invocation list, you can write: -[!code-csharp[csProgGuideDelegates#29](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#29)] +:::code language="csharp" source="./snippets/UsingDelegates.cs" id="GetInvocationList"::: -Delegates with more than one method in their invocation list derive from , which is a subclass of `System.Delegate`. The above code works in either case because both classes support `GetInvocationList`. +Delegates with more than one method in their invocation list derive from , which is a subclass of `System.Delegate`. The preceding code works in either case because both classes support `GetInvocationList`. -Multicast delegates are used extensively in event handling. Event source objects send event notifications to recipient objects that have registered to receive that event. To register for an event, the recipient creates a method designed to handle the event, then creates a delegate for that method and passes the delegate to the event source. The source calls the delegate when the event occurs. The delegate then calls the event handling method on the recipient, delivering the event data. The delegate type for a given event is defined by the event source. For more, see [Events](../events/index.md). +Multicast delegates are used extensively in event handling. Event source objects send event notifications to recipient objects that registered to receive that event. To register for an event, the recipient creates a method designed to handle the event, then creates a delegate for that method and passes the delegate to the event source. The source calls the delegate when the event occurs. The delegate then calls the event handling method on the recipient, delivering the event data. The event source defines the delegate type for a given event. For more, see [Events](../events/index.md). -Comparing delegates of two different types assigned at compile-time will result in a compilation error. If the delegate instances are statically of the type `System.Delegate`, then the comparison is allowed, but will return false at run time. For example: +Comparing delegates of two different types assigned at compile-time results in a compilation error. If the delegate instances are statically of the type `System.Delegate`, then the comparison is allowed, but returns false at run time. For example: -[!code-csharp[csProgGuideDelegates#30](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs#30)] +```csharp +delegate void Callback1(); +delegate void Callback2(); + +static void method(Callback1 d, Callback2 e, System.Delegate f) +{ + // Compile-time error. + Console.WriteLine(d == e); + + // OK at compile-time. False if the run-time type of f + // is not the same as that of d. + Console.WriteLine(d == f); +} +``` ## See also diff --git a/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs b/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs deleted file mode 100644 index 2673b4cb40ce1..0000000000000 --- a/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/Delegates.cs +++ /dev/null @@ -1,611 +0,0 @@ -using System; -using System.Windows.Forms; -//using System.Threading; -using System.Drawing; - -public delegate int PerformCalculation(int x, int y); -class DelegatesIntro -{ - - static int Add(int i, int j) - { - return i + j; - } - - static int Multiply(int a, int b) - { - return a * b; - } - - static int Calc(PerformCalculation p, int a, int b) - { - return p(a, b); - } - static void Main() - { - var perf = new PerformCalculation(Add); - - Console.WriteLine(Calc(Multiply, 5, 5)); - Console.WriteLine(Calc(Add, 2,2)); - PerformCalculation p = (a,b) => a * b; - p = (n,b) => n = 5 * n; - Console.WriteLine(p(6,6)); - - perf = Multiply; - Console.WriteLine(perf(2,3)); - - // Keep the console window open in debug mode. - Console.WriteLine("Press any key to exit."); - Console.ReadKey(); - } -} -//----------------------------------------------------------------------------- -class TestStuff -{ - class Temp - { - static Temp obj = new Temp(); - - // - // Declare a delegate. - delegate void WorkCallback(int x); - - // Define a named method. - void DoWork(int k) { /* ... */ } - - // Instantiate the delegate using the method as a parameter. - WorkCallback d = obj.DoWork; - // - } -} - -//----------------------------------------------------------------------------- -class TestStuffAgain -{ - // - // Declare a delegate. - delegate void NotifyCallback(string str); - - // Declare a method with the same signature as the delegate. - static void Notify(string name) - { - Console.WriteLine($"Notification received for: {name}"); - } - // - - public void DoWork() - { - // - // Create an instance of the delegate. - NotifyCallback del1 = new NotifyCallback(Notify); - // - - // - // C# 2.0 provides a simpler way to declare an instance of NotifyCallback. - NotifyCallback del2 = Notify; - // - - // - // Instantiate NotifyCallback by using an anonymous method. - NotifyCallback del3 = delegate(string name) - { Console.WriteLine($"Notification received for: {name}"); }; - // - - // - // Instantiate NotifyCallback by using a lambda expression. - NotifyCallback del4 = name => { Console.WriteLine($"Notification received for: {name}"); }; - // - } - - // - public delegate int PerformCalculation(int x, int y); - // - - class DelegateExamples - { - // - public delegate void Callback(string message); - // - - // - // Create a method for a delegate. - public static void DelegateMethod(string message) - { - Console.WriteLine(message); - } - // - - // - public static void MethodWithCallback(int param1, int param2, Callback callback) - { - callback("The number is: " + (param1 + param2).ToString()); - } - // - - void Method1(string message) { } - void Method2(string message) { } - - void DoWork() - { - // - // Instantiate the delegate. - Callback handler = DelegateMethod; - - // Call the delegate. - handler("Hello World"); - // - - // - MethodWithCallback(1, 2, handler); - // - - // - var obj = new MethodClass(); - Callback d1 = obj.Method1; - Callback d2 = obj.Method2; - Callback d3 = DelegateMethod; - - //Both types of assignment are valid. - Callback allMethodsDelegate = d1 + d2; - allMethodsDelegate += d3; - // - - // - //remove Method1 - allMethodsDelegate -= d1; - - // copy AllMethodsDelegate while removing d2 - Callback oneMethodDelegate = allMethodsDelegate - d2; - // - - // - int invocationCount = d1.GetInvocationList().GetLength(0); - // - } - } - - // - public class MethodClass - { - public void Method1(string message) { } - public void Method2(string message) { } - } - // - - // - delegate void Callback1(); - delegate void Callback2(); - - static void method(Callback1 d, Callback2 e, System.Delegate f) - { - // Compile-time error. - //Console.WriteLine(d == e); - - // OK at compile-time. False if the run-time type of f - // is not the same as that of d. - Console.WriteLine(d == f); - } - // -} - -//----------------------------------------------------------------------------- -namespace WrapNamedMethods1 -{ - // - // Declare a delegate - delegate void MultiplyCallback(int i, double j); - - class MathClass - { - static void Main() - { - MathClass m = new MathClass(); - - // Delegate instantiation using "MultiplyNumbers" - MultiplyCallback d = m.MultiplyNumbers; - - // Invoke the delegate object. - Console.WriteLine("Invoking the delegate using 'MultiplyNumbers':"); - for (int i = 1; i <= 5; i++) - { - d(i, 2); - } - - // Keep the console window open in debug mode. - Console.WriteLine("Press any key to exit."); - Console.ReadKey(); - } - - // Declare the associated method. - void MultiplyNumbers(int m, double n) - { - Console.Write(m * n + " "); - } - } - /* Output: - Invoking the delegate using 'MultiplyNumbers': - 2 4 6 8 10 - */ - // -} - -//----------------------------------------------------------------------------- -namespace WrapNamedMethods2 -{ - // - // Declare a delegate - delegate void Callback(); - - class SampleClass - { - public void InstanceMethod() - { - Console.WriteLine("A message from the instance method."); - } - - static public void StaticMethod() - { - Console.WriteLine("A message from the static method."); - } - } - - class TestSampleClass - { - static void Main() - { - var sc = new SampleClass(); - - // Map the delegate to the instance method: - Callback d = sc.InstanceMethod; - d(); - - // Map to the static method: - d = SampleClass.StaticMethod; - d(); - } - } - /* Output: - A message from the instance method. - A message from the static method. - */ - // -} - -//----------------------------------------------------------------------------- -namespace WrapCovariance -{ - // - class Mammals - { - } - - class Dogs : Mammals - { - } - - class Program - { - // Define the delegate. - public delegate Mammals HandlerMethod(); - - public static Mammals FirstHandler() - { - return null; - } - - public static Dogs SecondHandler() - { - return null; - } - - static void Main() - { - HandlerMethod handler1 = FirstHandler; - - // Covariance allows this delegate. - HandlerMethod handler2 = SecondHandler; - } - } - // -} - -//----------------------------------------------------------------------------- -namespace WrapContravariance -{ - public class Form1 : System.Windows.Forms.Form - { - // - System.DateTime lastActivity; - public Form1() - { - InitializeComponent(); - - lastActivity = new System.DateTime(); - this.textBox1.KeyDown += this.MultiHandler; //works with KeyEventArgs - this.button1.MouseClick += this.MultiHandler; //works with MouseEventArgs - } - - // Event handler for any event with an EventArgs or - // derived class in the second parameter - private void MultiHandler(object sender, System.EventArgs e) - { - lastActivity = System.DateTime.Now; - } - // - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.button1 = new System.Windows.Forms.Button(); - this.textBox1 = new System.Windows.Forms.TextBox(); - this.SuspendLayout(); - // - // button1 - // - this.button1.Location = new System.Drawing.Point(12, 73); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); - this.button1.TabIndex = 0; - this.button1.Text = "button1"; - this.button1.UseVisualStyleBackColor = true; - // - // textBox1 - // - this.textBox1.Location = new System.Drawing.Point(12, 38); - this.textBox1.Name = "textBox1"; - this.textBox1.Size = new System.Drawing.Size(100, 20); - this.textBox1.TabIndex = 1; - // - // Form1 - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(296, 266); - this.Controls.Add(this.textBox1); - this.Controls.Add(this.button1); - this.Name = "Form1"; - this.Text = "Form1"; - this.ResumeLayout(false); - this.PerformLayout(); - } - - #endregion - - private System.Windows.Forms.Button button1; - private System.Windows.Forms.TextBox textBox1; - } - - //----------------------------------------------------------------------------- - namespace WrapContravariance - { - // - using System; - - // Define a custom delegate that has a string parameter and returns void. - delegate void CustomCallback(string s); - - class TestClass - { - // Define two methods that have the same signature as CustomCallback. - static void Hello(string s) - { - Console.WriteLine($" Hello, {s}!"); - } - - static void Goodbye(string s) - { - Console.WriteLine($" Goodbye, {s}!"); - } - - static void Main() - { - // Declare instances of the custom delegate. - CustomCallback hiDel, byeDel, multiDel, multiMinusHiDel; - - // In this example, you can omit the custom delegate if you - // want to and use Action instead. - //Action hiDel, byeDel, multiDel, multiMinusHiDel; - - // Initialize the delegate object hiDel that references the - // method Hello. - hiDel = Hello; - - // Initialize the delegate object byeDel that references the - // method Goodbye. - byeDel = Goodbye; - - // The two delegates, hiDel and byeDel, are combined to - // form multiDel. - multiDel = hiDel + byeDel; - - // Remove hiDel from the multicast delegate, leaving byeDel, - // which calls only the method Goodbye. - multiMinusHiDel = multiDel - hiDel; - - Console.WriteLine("Invoking delegate hiDel:"); - hiDel("A"); - Console.WriteLine("Invoking delegate byeDel:"); - byeDel("B"); - Console.WriteLine("Invoking delegate multiDel:"); - multiDel("C"); - Console.WriteLine("Invoking delegate multiMinusHiDel:"); - multiMinusHiDel("D"); - } - } - /* Output: - Invoking delegate hiDel: - Hello, A! - Invoking delegate byeDel: - Goodbye, B! - Invoking delegate multiDel: - Hello, C! - Goodbye, C! - Invoking delegate multiMinusHiDel: - Goodbye, D! - */ - // - } - - //----------------------------------------------------------------------------- - namespace WrapDelegateBookstore - { - // - // A set of classes for handling a bookstore: - namespace Bookstore - { - using System.Collections; - - // Describes a book in the book list: - public struct Book - { - public string Title; // Title of the book. - public string Author; // Author of the book. - public decimal Price; // Price of the book. - public bool Paperback; // Is it paperback? - - public Book(string title, string author, decimal price, bool paperBack) - { - Title = title; - Author = author; - Price = price; - Paperback = paperBack; - } - } - - // Declare a delegate type for processing a book: - // - public delegate void ProcessBookCallback(Book book); - // - - // Maintains a book database. - public class BookDB - { - // List of all books in the database: - ArrayList list = new ArrayList(); - - // Add a book to the database: - public void AddBook(string title, string author, decimal price, bool paperBack) - { - list.Add(new Book(title, author, price, paperBack)); - } - - // Call a passed-in delegate on each paperback book to process it: - public void ProcessPaperbackBooks(ProcessBookCallback processBook) - { - foreach (Book b in list) - { - if (b.Paperback) - // Calling the delegate: - // - processBook(b); - // - } - } - } - } - - // Using the Bookstore classes: - namespace BookTestClient - { - using Bookstore; - - // Class to total and average prices of books: - class PriceTotaller - { - int countBooks = 0; - decimal priceBooks = 0.0m; - - internal void AddBookToTotal(Book book) - { - countBooks += 1; - priceBooks += book.Price; - } - - internal decimal AveragePrice() - { - return priceBooks / countBooks; - } - } - - // Class to test the book database: - class Test - { - // Print the title of the book. - static void PrintTitle(Book b) - { - Console.WriteLine($" {b.Title}"); - } - - // Execution starts here. - static void Main() - { - BookDB bookDB = new BookDB(); - - // Initialize the database with some books: - AddBooks(bookDB); - - // Print all the titles of paperbacks: - Console.WriteLine("Paperback Book Titles:"); - - // Create a new delegate object associated with the static - // method Test.PrintTitle: - // - bookDB.ProcessPaperbackBooks(PrintTitle); - // - - // Get the average price of a paperback by using - // a PriceTotaller object: - PriceTotaller totaller = new PriceTotaller(); - - // Create a new delegate object associated with the nonstatic - // method AddBookToTotal on the object totaller: - // - bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal); - // - - Console.WriteLine("Average Paperback Book Price: ${0:#.##}", - totaller.AveragePrice()); - } - - // Initialize the book database with some test books: - static void AddBooks(BookDB bookDB) - { - bookDB.AddBook("The C Programming Language", "Brian W. Kernighan and Dennis M. Ritchie", 19.95m, true); - bookDB.AddBook("The Unicode Standard 2.0", "The Unicode Consortium", 39.95m, true); - bookDB.AddBook("The MS-DOS Encyclopedia", "Ray Duncan", 129.95m, false); - bookDB.AddBook("Dogbert's Clues for the Clueless", "Scott Adams", 12.00m, true); - } - } - } - /* Output: - Paperback Book Titles: - The C Programming Language - The Unicode Standard 2.0 - Dogbert's Clues for the Clueless - Average Paperback Book Price: $23.97 - */ - // - } -} diff --git a/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/csrefDelegates.csproj b/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/csrefDelegates.csproj deleted file mode 100644 index 915ed89ea7182..0000000000000 --- a/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideDelegates/CS/csrefDelegates.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - Exe - net48 - - DelegatesIntro - - - - - - -