¿Cuándo usarías delegados en C#? [cerrado]


¿Cuál es su uso de delegados en C#?

Author: Bill the Lizard, 2008-10-10

20 answers

Ahora que tenemos expresiones lambda y métodos anónimos en C#, uso delegados mucho más. En C # 1, donde siempre había que tener un método separado para implementar la lógica, usar un delegado a menudo no tenía sentido. En estos días uso delegados para:

  • Controladores de eventos (para GUI y más)
  • Hilos de partida
  • Callbacks (por ejemplo, para API asincrónicas)
  • LINQ y similares (List.Find etc)
  • En cualquier otro lugar donde quiera aplicar efectivamente el código "plantilla" con alguna lógica especializada en el interior (donde el delegado proporciona la especialización)
 97
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-02-19 16:19:03

Los delegados son muy útiles para muchos propósitos.

Uno de esos propósitos es usarlos para filtrar secuencias de datos. En este caso, usaría un delegado predicado que acepta un argumento y devuelve true o false dependiendo de la implementación del delegado en sí.

Aquí hay un ejemplo tonto-estoy seguro de que puede extrapolar algo más útil de esto:

using System;
using System.Linq;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<String> names = new List<String>
        {
            "Nicole Hare",
            "Michael Hare",
            "Joe Hare",
            "Sammy Hare",
            "George Washington",
        };

        // Here I am passing "inMyFamily" to the "Where" extension method
        // on my List<String>.  The C# compiler automatically creates 
        // a delegate instance for me.
        IEnumerable<String> myFamily = names.Where(inMyFamily);

        foreach (String name in myFamily)
            Console.WriteLine(name);
    }

    static Boolean inMyFamily(String name)
    {
        return name.EndsWith("Hare");
    }
}
 27
Author: Andrew Hare,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-31 19:11:41

Encontré otra respuesta interesante:

Un compañero de trabajo me acaba de hacer esta pregunta - ¿cuál es el punto de los delegados en.NET? Mi respuesta fue muy corta y una que no había encontrado en línea: retrasar la ejecución de un método.

Fuente: LosTechies

Al igual que LINQ está haciendo.

 13
Author: Maxime Rouiller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-16 18:12:31

Puede usar delegados para declarar variables y parámetros de tipo función.

Ejemplo

Considere el patrón de "préstamo de recursos". Desea controlar la creación y limpieza de un recurso, mientras permite que el código del cliente "tome prestado" el recurso en el medio.

Esto declara un tipo de delegado.

public delegate void DataReaderUser( System.Data.IDataReader dataReader );

Cualquier método que coincida con esta firma se puede utilizar para crear instancias de un delegado de este tipo. En C # 2.0, esto se puede hacer implícitamente, simplemente usando nombre del método, así como mediante el uso de métodos anónimos.

Este método utiliza el tipo como parámetro. Nótese la invocación del delegado.

public class DataProvider
{
    protected string _connectionString;

    public DataProvider( string psConnectionString )
    {
        _connectionString = psConnectionString;
    }

    public void UseReader( string psSELECT, DataReaderUser readerUser )
    {
        using ( SqlConnection connection = new SqlConnection( _connectionString ) )
        try
        {
            SqlCommand command = new SqlCommand( psSELECT, connection );
            connection.Open();
            SqlDataReader reader = command.ExecuteReader();

            while ( reader.Read() )
                readerUser( reader );  // the delegate is invoked
        }
        catch ( System.Exception ex )
        {
            // handle exception
            throw ex;
        }
    }
}

La función se puede llamar con un método anónimo de la siguiente manera. Tenga en cuenta que el método anónimo puede usar variables declaradas fuera de de sí mismo. Esto es extremadamente útil (aunque el ejemplo es un poco artificial).

string sTableName = "test";
string sQuery = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='" + sTableName + "'";

DataProvider.UseReader( sQuery,
    delegate( System.Data.IDataReader reader )
    {
        Console.WriteLine( sTableName + "." + reader[0] );
    } );
 12
Author: harpo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 13:27:07

Los delegados a menudo se pueden usar en lugar de una interfaz con un método, un ejemplo común de esto sería el patrón del observador. En otros idiomas, si desea recibir una notificación de que algo ha sucedido, puede definir algo como:

class IObserver{ void Notify(...); }

En C # esto se expresa más comúnmente usando eventos, donde el controlador es un delegado, por ejemplo:

myObject.SomeEvent += delegate{ Console.WriteLine("..."); };

Otro gran lugar para usar delegados si cuando tienes que pasar un predicado a una función, por ejemplo cuando selección de un conjunto de elementos de una lista:

myList.Where(i => i > 10);

Lo anterior es un ejemplo de la sintaxis lambda, que también podría haber sido escrito de la siguiente manera:

myList.Where(delegate(int i){ return i > 10; });

Otro lugar donde puede ser útil usar delegados es registrar funciones de fábrica, por ejemplo:

myFactory.RegisterFactory(Widgets.Foo, () => new FooWidget());
var widget = myFactory.BuildWidget(Widgets.Foo);

Espero que esto ayude!

 10
Author: jonnii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-31 19:04:55

Estoy llegando a esto muy tarde, pero estaba teniendo problemas para averiguar el propósito de los delegados de hoy y escribí dos programas simples que dan la misma salida que creo que explica bien su propósito.

NoDelegados.cs

using System;

public class Test {
    public const int MAX_VALUE = 255;
    public const int MIN_VALUE = 10;

    public static void checkInt(int a) {
        Console.Write("checkInt result of {0}: ", a);
        if (a < MAX_VALUE && a > MIN_VALUE)
            Console.WriteLine("max and min value is valid");
        else
            Console.WriteLine("max and min value is not valid");
    }

    public static void checkMax(int a) {
        Console.Write("checkMax result of {0}: ", a);
        if (a < MAX_VALUE)
            Console.WriteLine("max value is valid");
        else
            Console.WriteLine("max value is not valid");
    }

    public static void checkMin(int a) {
        Console.Write("checkMin result of {0}: ", a);
        if (a > MIN_VALUE)
            Console.WriteLine("min value is valid");
        else
            Console.WriteLine("min value is not valid");
        Console.WriteLine("");
    }
}

public class Driver {
    public static void Main(string [] args) {
        Test.checkInt(1);
        Test.checkMax(1);
        Test.checkMin(1);

        Test.checkInt(10);
        Test.checkMax(10);
        Test.checkMin(10);

        Test.checkInt(20);
        Test.checkMax(20);
        Test.checkMin(20);

        Test.checkInt(30);
        Test.checkMax(30);
        Test.checkMin(30);

        Test.checkInt(254);
        Test.checkMax(254);
        Test.checkMin(254);

        Test.checkInt(255);
        Test.checkMax(255);
        Test.checkMin(255);

        Test.checkInt(256);
        Test.checkMax(256);
        Test.checkMin(256);
    }
}

Delegados.cs

using System;

public delegate void Valid(int a);

public class Test {
    public const int MAX_VALUE = 255;
    public const int MIN_VALUE = 10;

    public static void checkInt(int a) {
        Console.Write("checkInt result of {0}: ", a);
        if (a < MAX_VALUE && a > MIN_VALUE)
            Console.WriteLine("max and min value is valid");
        else
            Console.WriteLine("max and min value is not valid");
    }

    public static void checkMax(int a) {
        Console.Write("checkMax result of {0}: ", a);
        if (a < MAX_VALUE)
            Console.WriteLine("max value is valid");
        else
            Console.WriteLine("max value is not valid");
    }

    public static void checkMin(int a) {
        Console.Write("checkMin result of {0}: ", a);
        if (a > MIN_VALUE)
            Console.WriteLine("min value is valid");
        else
            Console.WriteLine("min value is not valid");
        Console.WriteLine("");
    }
}

public class Driver {
    public static void Main(string [] args) {
        Valid v1 = new Valid(Test.checkInt);
        v1 += new Valid(Test.checkMax);
        v1 += new Valid(Test.checkMin);
        v1(1);
        v1(10);
        v1(20);
        v1(30);
        v1(254);
        v1(255);
        v1(256);
    }
}
 10
Author: will,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-05 22:01:00

Un uso ligeramente diferente es acelerar la reflexión; es decir, en lugar de usar reflexión cada vez, puede usar Delegate.CreateDelegate para crear un delegado (escrito) a un método (a MethodInfo), y llamar a ese delegado en su lugar. Esto es entonces mucho más rápido por llamada, ya que las comprobaciones ya se han hecho.

Con Expression, también puede hacer lo mismo para crear código sobre la marcha , por ejemplo, puede crear fácilmente un Expression que represente el operador + para un tipo elegido en tiempo de ejecución (para proporcionar soporte al operador para genéricos, que el lenguaje no proporciona); y puede compilar un Expression a un delegado escrito - trabajo hecho.

 5
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 13:24:55

Los delegados se usan cada vez que se usan eventos - ese es el mecanismo por el cual funcionan.

Además, los delegados son muy útiles para cosas como el uso de consultas LINQ. Por ejemplo, muchas consultas LINQ toman un delegado (a menudo Func<T,TResult>) que se puede usar para filtrar.

 5
Author: Reed Copsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-07-31 19:01:07

Suscribiendo eventhandlers a eventos

 4
Author: Manu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 13:05:11

Un ejemplo podría ser como se ve aquí. Tiene un método para procesar un objeto que cumple con ciertos requisitos. Sin embargo, desea poder procesar el objeto de varias maneras. En lugar de tener que crear métodos separados, simplemente puede asignar un método coincidente que procesa el objeto a un delegado y pasar el delegado al método que selecciona los objetos. De esta manera, puede asignar diferentes métodos al método de un selector. Traté de hacer esto fácilmente comprensible.

 2
Author: rookie1024,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-11 04:14:24

Utilizo delegados para comunicarme con hilos.

Por ejemplo, podría tener una aplicación de win forms que descarga un archivo. La aplicación inicia un hilo de trabajo para realizar la descarga (lo que evita que la GUI se bloquee). El hilo de trabajo utiliza delegados para enviar mensajes de estado (por ejemplo, el progreso de descarga) de vuelta al programa principal, de modo que la GUI puede actualizar la barra de estado.

 1
Author: Danny Frencham,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-21 03:41:02
  1. Para el controlador de eventos

  2. Para pasar el método en un método parámetros

 0
Author: Patrick Desjardins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 13:07:52

La primera línea de uso es reemplazar el patrón Observer/Observable (eventos). El segundo, una bonita y elegante versión del patrón de Estrategia. Se pueden reunir varios otros usos, aunque creo que más esotéricos que estos dos primeros.

 0
Author: x0n,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 13:08:03

Eventos, otras operaciones anynch

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 13:08:13

En cualquier momento que desee encapsular el comportamiento, pero invoque de manera uniforme. Controladores de eventos, funciones de devolución de llamada, etc. Puedes lograr cosas similares usando Interfaces y casts, pero a veces, el comportamiento no está necesariamente ligado a un tipo o objeto. A veces solo tienes un comportamiento que necesitas encapsular.

 0
Author: Bob King,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 13:09:56

Inicialización de parámetro perezoso! Además de todas las respuestas anteriores (patrón de estrategia, patrón de observador, etc.), los delegados le permiten manejar la inicialización perezosa de los parámetros. Por ejemplo, supongamos que tiene una función Download () que lleva bastante tiempo y devuelve un determinado DownloadedObject. Este objeto es consumido por un Almacenamiento dependiendo de ciertas Condiciones. Por lo general, usted:

storage.Store(conditions, Download(item))

Sin embargo, con delegados (más precisamente, lambdas) puede hacer lo siguiente, cambiando la firma de la tienda para que reciba una Condición y un Func y utilícelo así:

storage.Store(conditions, (item) => Download(item))

Por lo tanto, storage solo evaluará el delegado si es necesario, ejecutando la descarga dependiendo de las Condiciones.

 0
Author: Santiago Palladino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 13:18:12

Uso de delegados

  1. Manejo de eventos
  2. Multi Casting
 0
Author: Rajeshwaran S P,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-10 13:37:41

El parámetro de comparación en In Array.Sort (T [] array, Comparación de comparación), Lista.Sort (Comparación comparación), etc

 0
Author: GregUzelac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-11 15:12:19

Por lo que sé, los delegados se pueden convertir en punteros de función. Esto hace la vida mucho más fácil cuando se interopera con código nativo que toma punteros de función, ya que pueden estar efectivamente orientados a objetos, a pesar de que el programador original no hizo ninguna provisión para que eso sucediera.

 0
Author: Puppy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-25 16:25:02

Los delegados se utilizan para llamar a un método por su referencia. Por ejemplo:

  delegate void del_(int no1,int no2);
class Math
{
   public static void add(int x,int y)
   {
     Console.WriteLine(x+y);
   }
   public static void sub(int x,int y)
   {
     Console.WriteLine(x-y);
   }
}



    class Program
    {
        static void Main(string[] args)
        {
            del_ d1 = new del_(Math.add);
            d1(10, 20);
            del_ d2 = new del_(Math.sub);
            d2(20, 10);
            Console.ReadKey();
        }
    }
 0
Author: mahesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-26 11:38:30