2008-10-10 20 views
99

¿Cuál es su uso de delegados en C#?¿Cuándo usarías delegados en C#?

+2

¿Quiere decir delegados en el sistema de tipo .NET o en la sintaxis del delegado de C#? ¿Quiere decir "cuándo utiliza la sintaxis de delegado en lugar de la sintaxis de expresión lambda" o quiere decir "¿cuándo utiliza delegados en lugar de clases/interfaces/métodos virtuales/etc."? – Niki

+0

[http://stackoverflow.com/questions/1137431/are-net-delegates-used-for-events](http://stackoverflow.com/questions/1137431/are-net-delegates-used-for-events) – Raghav

Respuesta

97

Ahora que tenemos las expresiones lambda y métodos anónimos en C#, yo uso mucho más delegados. 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. En estos días me utilizan para delegados:

  • Los controladores de eventos (para la interfaz gráfica de usuario y más)
  • hilos partir
  • Callbacks (por ejemplo, para las API asíncronas)
  • LINQ y similares (List.Find etc)
  • en cualquier otro lugar donde quiero aplicar efectivamente código de "plantilla" con cierta lógica especializada en el interior (donde el delegado proporciona la especialización)
+0

¿Vale la pena mencionar el "push" en Push LINQ? –

+3

No estoy seguro de cómo lo explicaría brevemente sin hacer las cosas más confusas :) (Discutible, está cubierto por los controladores de eventos, LINQ, y el bit de templaty de todos modos! –

+1

Tu primera frase no tiene mucho sentido. – senfo

4

suscriban a manejadores de sucesos eventos

0
  1. Para controlador de eventos

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

0

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

0

Eventos, otras operaciones anynch

0

En cualquier momento que desea encapsular el comportamiento, pero invocar de una 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 relacionado con un tipo o objeto. Algunas veces solo tienes un comportamiento que necesitas encapsular.

0

¡Inicialización de parámetros vagos! 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, lo haría:

storage.Store(conditions, Download(item)) 

Sin embargo, con los delegados (más precisamente, lambdas) se puede hacer lo siguiente, cambiando la firma de la tienda para que reciba una condición y un elemento de Func <, DownloadedObject > y el uso de esta manera:

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

por lo tanto, el almacenamiento sólo se evaluará el delegado si es necesario, la ejecución de descarga dependiendo de las condiciones.

+0

Punto menor, pero re "más precisamente, lambdas" - podría hacer lo mismo con un método anónimo en C# 2.0, aunque sería más v erbose: delegate (ítem ItemType) {[return] Download (item);} –

+0

Claro, al igual que LINQ: lambdas no son más que azúcar sintáctico para los delegados. Simplemente hicieron a los delegados más accesibles. –

+0

Las lambdas son algo más que simples delegados, ya que son convertibles en árboles de expresión y delegados. –

5

Un uso ligeramente diferente es para 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 (un MethodInfo) y llamar a ese delegado en su lugar. Esto es entonces 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 el código en el momento - por ejemplo, puede crear fácilmente un Expression que representa el operador + para un tipo elegido en tiempo de ejecución (para proporcionar soporte del operador para los genéricos, que la el lenguaje no proporciona); y puede compilar un Expression a un delegado tipeado - trabajo hecho.

12

Puede usar delegados para declarar variables y parámetros con funciones.

Ejemplo

Considérese el patrón "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 utilizar 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 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 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]); 
    }); 
0

Uso de delegados

  1. Manejo de Eventos
  2. Fundición Multi
0

La comparación PARAM en En Array.Sort (T [] array, de comparación de comparación), list.sort (Comparación de comparación), etc.

13

Encontrado 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 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.

+0

+ 1..no lo había pensado así. Buen punto – Luke101

1

Uso delegados para comunicarme con los hilos.

Por ejemplo, podría tener una aplicación de formularios de 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.

27

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

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

Aquí es un ejemplo tonto - Estoy seguro de que se pueda extrapolar algo más útil fuera 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"); 
    } 
} 
+4

¿dónde está el delegado? –

+11

El método 'static Boolean inMyFamily (String name)' es el delegado. Donde toma un delegado como parámetro. Dado que los delegados son solo indicadores de función cuando pasa el nombre del método al '.Where (delegate)' que se convierte en el delegado. Como inMyFamily devuelve un tipo booleano, en realidad se lo considera un predicado. Los predicados son solo delegados que devuelven booleanos. –

+4

"Los predicados son solo delegados que devuelven booleanos". +1 – daehaai

5

Los delegados se utilizan cada vez que utilice eventos - que es el mecanismo por el cual trabajan.

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.

10

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 ha ocurrido algo puede definir algo como:

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

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

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

Otro gran lugar para utilizar delegados si cuando tiene que pasar un predicado en una función, por ejemplo, cuando la 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 el uso de los delegados es registrar las funciones de fábrica, por ejemplo:

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

¡Espero que esto ayude!

+0

Buenos ejemplos con sintaxis ... Gracias ... :) – Raghu

0

Por lo que sé, los delegados se pueden convertir a punteros a funciones. 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.

0

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

voy a entrar en este muy tarde, pero yo estaba teniendo problemas para averiguar el propósito de delegados hoy y escribió 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); 
    } 
} 
2

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.