c# eventos - ¿Cuándo usarías delegados en C #?





tipos los (17)


Encontré otra respuesta interesante:

Un compañero de trabajo me acaba de hacer esta pregunta: ¿qué sentido tienen los delegados en .NET? Mi respuesta fue muy breve y una que no había encontrado en línea: para retrasar la ejecución de un método.

Fuente: LosTechies

Al igual que LINQ está haciendo.

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




Me estoy metiendo en esto muy tarde pero estaba teniendo problemas para entender el propósito de los delegados de hoy y escribí dos programas sencillos que dan el mismo resultado que creo que explica bien su propósito.

NoDelegates.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);
    }
}

Delegates.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);
    }
}



Yo uso delegados para comunicarme con los hilos.

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




  1. Para el controlador de eventos

  2. Pasar el método en los parámetros de un método




Los delegados se usan cada vez que usa eventos: ese es el mecanismo por el que 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.




Inicialización de parámetros perezosos! Además de todas las respuestas anteriores (patrón de estrategia, patrón de observador, etc.), los delegados le permiten manejar la inicialización lenta de los parámetros. Por ejemplo, supongamos que tiene una función Descargar () 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 los delegados (más precisamente, lambdas) puede hacer lo siguiente, cambiando la firma de la tienda para que reciba una Condición y un Func <Artículo, un Objeto Descargado> y úselo de esta manera:

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

Por lo tanto, el almacenamiento solo evaluará al delegado si es necesario, y ejecutará la descarga en función de las Condiciones.




Un uso ligeramente diferente es acelerar la reflexión; es decir, en lugar de usar el reflejo cada vez, puede usar Delegate.CreateDelegate para crear un delegado (tipado) en un método ( MethodInfo ), y llamar a ese delegado en su lugar. Esto es mucho más rápido por llamada, ya que los controles 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 una Expression que represente el operador + para un tipo elegido en tiempo de ejecución (para proporcionar soporte de operador para genéricos, que el lenguaje no proporcionar); y puede compilar una Expression a un delegado tipeado - trabajo hecho.




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();
        }
    }



Cada vez que quiera encapsular el comportamiento, invocarlo de manera uniforme. Controladores de eventos, funciones de devolución de llamada, etc. Puede lograr cosas similares utilizando interfaces y conversiones, pero a veces, el comportamiento no está necesariamente vinculado a un tipo u objeto . Algunas veces solo tienes un comportamiento que necesitas encapsular.




Hasta donde yo sé, los delegados se pueden convertir a indicadores de función. Esto hace la vida MUCHO más fácil cuando se interopera con código nativo que toma punteros a las funciones, ya que pueden orientarse de manera efectiva a los objetos, aunque el programador original no hizo ninguna provisión para que eso suceda.




Los delegados a menudo se pueden utilizar 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, podría definir algo como:

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

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

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

Otro gran lugar para usar delegados es cuando tienes que pasar un predicado a una función, por ejemplo cuando seleccionas 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 haberse 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!




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 la limpieza de un recurso, al mismo tiempo que permite que el código del cliente "tome prestado" el recurso intermedio.

Esto declara un tipo de delegado.

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

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

Este método usa el tipo como un parámetro. Tenga en cuenta 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 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] );
    } );



Eventos, otras operaciones de anynch




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

  • Manejadores de eventos (para GUI y más)
  • Hilos de inicio
  • Devolución de llamada (por ejemplo, para API asíncronas)
  • LINQ y similares (List.Find, etc.)
  • En cualquier lugar donde quiera aplicar efectivamente el código de "plantilla" con alguna lógica especializada dentro (donde el delegado proporciona la especialización)



Un ejemplo podría ser como se ve here . Usted tiene un método para procesar un objeto que cumple con ciertos requisitos. Sin embargo, desea poder procesar el objeto de múltiples maneras. En lugar de tener que crear métodos separados, puede simplemente asignar un método de coincidencia que procese el objeto a un delegado y pasar el delegado al método que selecciona los objetos. De esta forma, puede asignar diferentes métodos al método de un solo selector. Traté de hacer esto fácilmente comprensible.




suscribiendo eventhandlers a eventos




Esta pregunta aparece en el Capítulo 10 de " C # Step by Step 2013 "

El autor utiliza un doble for-loop para iterar a través de un par de enumeradores (para crear un mazo de cartas completo):

class Pack
{
    public const int NumSuits = 4;
    public const int CardsPerSuit = 13;
    private PlayingCard[,] cardPack;

    public Pack()
    {
        this.cardPack = new PlayingCard[NumSuits, CardsPerSuit];
        for (Suit suit = Suit.Clubs; suit <= Suit.Spades; suit++)
        {
            for (Value value = Value.Two; value <= Value.Ace; value++)
            {
                cardPack[(int)suit, (int)value] = new PlayingCard(suit, value);
            }
        }
    }
}

En este caso, Suit y Value son ambas enumeraciones:

enum Suit { Clubs, Diamonds, Hearts, Spades }
enum Value { Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace}

y PlayingCard es un objeto de tarjeta con un Suit y Value definidos:

class PlayingCard
{
    private readonly Suit suit;
    private readonly Value value;

    public PlayingCard(Suit s, Value v)
    {
        this.suit = s;
        this.value = v;
    }
}




c# .net delegates