Procedimiento Declarar un delegado, crear instancias del mismo y utilizarlo (Guía de programación de C#)How to: Declare, Instantiate, and Use a Delegate (C# Programming Guide)

En C# 1.0 y versiones posteriores, los delegados se pueden declarar como se muestra en el ejemplo siguiente.In C# 1.0 and later, delegates can be declared as shown in the following example.

// Declare a delegate.
delegate void Del(string str);

// Declare a method with the same signature as the delegate.
static void Notify(string name)
{
    Console.WriteLine($"Notification received for: {name}");
}
// Create an instance of the delegate.
Del del1 = new Del(Notify);

C# 2.0 ofrece una forma más sencilla de escribir la declaración anterior, tal como se muestra en el ejemplo siguiente.C# 2.0 provides a simpler way to write the previous declaration, as shown in the following example.

// C# 2.0 provides a simpler way to declare an instance of Del.
Del del2 = Notify;

En C# 2.0 y versiones posteriores, también es posible utilizar un método anónimo para declarar e inicializar un delegado, como se muestra en el ejemplo siguiente.In C# 2.0 and later, it is also possible to use an anonymous method to declare and initialize a delegate, as shown in the following example.

// Instantiate Del by using an anonymous method.
Del del3 = delegate(string name)
    { Console.WriteLine($"Notification received for: {name}"); };

En C# 3.0 y versiones posteriores, también se pueden declarar los delegados y crear una instancia de ellos mediante una expresión lambda, como se muestra en el ejemplo siguiente.In C# 3.0 and later, delegates can also be declared and instantiated by using a lambda expression, as shown in the following example.

// Instantiate Del by using a lambda expression.
Del del4 = name =>  { Console.WriteLine($"Notification received for: {name}"); };

Para obtener más información, vea Expresiones lambda.For more information, see Lambda Expressions.

En el ejemplo siguiente se ilustra cómo declarar un delegado, crear una instancia del mismo y utilizarloThe following example illustrates declaring, instantiating, and using a delegate. La clase BookDB encapsula una base de datos de una librería que mantiene una base de datos de libros.The BookDB class encapsulates a bookstore database that maintains a database of books. Expone un método ProcessPaperbackBooks, que busca todos los libros de bolsillo en la base de datos y llama a un delegado para cada uno.It exposes a method, ProcessPaperbackBooks, which finds all paperback books in the database and calls a delegate for each one. El tipo delegate utilizado se denomina ProcessBookDelegate.The delegate type that is used is named ProcessBookDelegate. La clase Test utiliza esta clase para imprimir los títulos y el precio medio de los libros de bolsillo.The Test class uses this class to print the titles and average price of the paperback books.

El uso de delegados promueve una separación adecuada de la funcionalidad entre la base de datos de la librería y el código de cliente.The use of delegates promotes good separation of functionality between the bookstore database and the client code. El código de cliente no sabe cómo se almacenan los libros ni cómo el código de la biblioteca encuentra los libros de bolsillo.The client code has no knowledge of how the books are stored or how the bookstore code finds paperback books. El código de la librería no sabe qué procesamiento se realiza con los libros de bolsillo después de que los encuentra.The bookstore code has no knowledge of what processing is performed on the paperback books after it finds them.

EjemploExample

// 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 ProcessBookDelegate(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(ProcessBookDelegate 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
*/

Programación sólidaRobust Programming

  • Declaración de un delegado.Declaring a delegate.

    La instrucción siguiente declara un nuevo tipo de delegado.The following statement declares a new delegate type.

    public delegate void ProcessBookDelegate(Book book);
    

    Cada tipo de delegado describe el número y los tipos de argumentos, y el tipo del valor devuelto de los métodos que puede encapsular.Each delegate type describes the number and types of the arguments, and the type of the return value of methods that it can encapsulate. Siempre que se necesite un nuevo conjunto de tipos de argumentos o de tipos de valores devueltos, se debe declarar un nuevo tipo de delegado.Whenever a new set of argument types or return value type is needed, a new delegate type must be declared.

  • Creación de instancias de un delegado.Instantiating a delegate.

    Después de haber declarado un tipo de delegado, debe crearse un objeto delegado y asociarse con un método particular.After a delegate type has been declared, a delegate object must be created and associated with a particular method. En el ejemplo anterior, esto se hace pasando el método PrintTitle al método ProcessPaperbackBooks como en el ejemplo siguiente:In the previous example, you do this by passing the PrintTitle method to the ProcessPaperbackBooks method as in the following example:

    bookDB.ProcessPaperbackBooks(PrintTitle);
    

    Esto crea un objeto delegado nuevo asociado con el método estático Test.PrintTitle.This creates a new delegate object associated with the static method Test.PrintTitle. De forma similar, el método no estático AddBookToTotal del objeto totaller se pasa como en el ejemplo siguiente:Similarly, the non-static method AddBookToTotal on the object totaller is passed as in the following example:

    bookDB.ProcessPaperbackBooks(totaller.AddBookToTotal);
    

    En ambos casos, se pasa un nuevo objeto delegado al método ProcessPaperbackBooks.In both cases a new delegate object is passed to the ProcessPaperbackBooks method.

    Después de que se ha creado un delegado, el método con el que está asociado nunca cambia; los objetos delegados son inmutables.After a delegate is created, the method it is associated with never changes; delegate objects are immutable.

  • Llamada a un delegado.Calling a delegate.

    Después de haber creado un objeto delegado, este suele pasarse a otro código que llamará al delegado.After a delegate object is created, the delegate object is typically passed to other code that will call the delegate. La llamada a un objeto delegado se realiza mediante la utilización del nombre de dicho objeto, seguido de los argumentos entre paréntesis que se deben pasar al delegado.A delegate object is called by using the name of the delegate object, followed by the parenthesized arguments to be passed to the delegate. A continuación se expone un ejemplo de llamada a un delegado:Following is an example of a delegate call:

    processBook(b);
    

    Se puede llamar a un delegado de forma sincrónica, como en este ejemplo, o bien de forma asincrónica con los métodos BeginInvoke y EndInvoke.A delegate can be either called synchronously, as in this example, or asynchronously by using BeginInvoke and EndInvoke methods.

Vea tambiénSee also