2010-04-20 16 views
47

He leído dos libros, un montón de ejemplos. Todavía tienen poco sentido para mí. Probablemente podría escribir algún código que use delegados, pero no tengo idea de por qué. ¿Soy el único con este problema o soy solo un idiota? Si alguien puede explicarme cuándo, dónde y por qué usaría un delegado, te amaré para siempre.¿Por qué tratar de entender a los delegados es como tratar de entender la naturaleza del universo?

+3

¿entiende punteros de función y por qué te gustaría usarlos en C++? –

+0

No, yo no, ¿aprendería eso a entender a los delegados? – Kin

+5

@Kin, si entendiera los indicadores de función, pensaría que los delegados fueron un regalo del cielo. –

Respuesta

18

Los delegados son solo una forma de pasar una función en una variable.

Tiene una función delegada para hacer una devolución de llamada. Como cuando se hace IO asíncrono, se pasa una función delegada (una función que se ha escrito con el parámetro de delegado) que se invocará cuando los datos se hayan leído en el disco.

+1

. De hecho, esto tiene más sentido que lo que he visto. ahora, gracias. – Kin

+5

En mi opinión, parte de la curva inicial de aprendizaje proviene de la sintaxis del delegado. Cuando comienzas por primera vez, parece una gran ceremonia. Para empeorar las cosas, se puede sentir como todos los demás, pero usted piensa que todo es muy simple. (No estoy criticando la sintaxis ... solo recuerdo mi experiencia de aprendizaje.) – Larsenal

+2

Se siente así. He visto ejemplos que intentan explicarlos, tiene ejemplos y procede a decir "¿Ahora no es tan bueno?", Mientras me estaba rascando la cabeza. – Kin

2

Tal vez esto ayuda:

  • Un delegado es un tipo (definir una firma de método)
  • Una instancia delegada es una referencia a un método (función de puntero AKA)
  • una devolución de llamada es un parámetro de un tipo delegado
  • un evento es un (tipo de) la propiedad de un tipo delegado

El propósito de los delegados es tha t puede tener variables/campos/parámetros/propiedades (eventos) que 'mantienen' una función. Eso le permite almacenar/pasar una función específica que seleccione el tiempo de ejecución. Sin él, cada llamada de función debe ser arreglada en tiempo de compilación.

La sintaxis que involucra los delegados (o eventos) puede ser un poco intimidante al principio, esto tiene 2 razones:

  1. sencilla puntero a funciones como en C/C++ no sería de tipo seguro, en .NET el compilador en realidad genera una clase a su alrededor, y luego trata de ocultar eso tanto como sea posible.

  2. delegados son la piedra angular de LINQ, y hay una gran evolución desde la especificación de todo en C# 1 a través de métodos anónimos (C# 2) a lambdas (C# 3).

Familiarícese con 1 o 2 patrones estándar.

+0

Eso ayuda un poco, nunca he visto un evento descrito como una propiedad. – Kin

+0

@Kin, usualmente vemos la notación corta de un evento. La notación completa utiliza add/remove en lugar de los accessors get/set de una propiedad normal, consulte http://msdn.microsoft.com/en-us/library/cc713642.aspx –

4

Como otras personas han mencionado, los delegados son útiles para las devoluciones de llamadas. Son útiles para toda una carga de otras cosas también. Por ejemplo, en un juego en el que he estado trabajando recientemente, las balas hacen cosas diferentes cuando golpean (algunas hacen daño, algunas realmente aumentan la salud de la persona que golpean, otras no hacen daño pero envenenan al objetivo, etc.). La forma en programación orientada a objetos clásica de hacer esto sería una clase de bala base y una carga de subclases

Bullet 
    DamageBullet 
    HealBullet 
    PoisonBullet 
    DoSomethingElseBullet 
    PoisonAndThenHealBullet 
    FooAndBarBullet 
    .... 

Con este patrón, tengo que definir una nueva subclase cada vez que quiero un nuevo comportamiento en una bala, que es una lío y conduce a una gran cantidad de código duplicado. En cambio, lo resolví con delegados. Una viñeta tiene un delegado de OnHit, que se llama cuando la viñeta golpea un objeto, y por supuesto puedo hacer que delegue lo que quiera. Así que ahora puedo crear viñetas como esta

new Bullet(DamageDelegate) 

Lo que obviamente es una forma mucho más agradable de hacer las cosas.

En lenguajes funcionales, se tiende a ver mucho más de este tipo de cosas.

+7

¿Entonces lo que estás diciendo es que no hay SilverBullet? – quillbreaker

+0

Tonterías, son simplemente caras y solo tienden a usarse JIT;) – jcolebrand

4

Un delegado es un contenedor simple que sabe en qué lugar de la memoria de la máquina se encuentra un método específico.

Todos los delegados tienen un método Invoke(...), por lo tanto, cuando alguien tiene un delegado, puede ejecutarlo, sin tener que saber o molestar realmente lo que ese método realmente hace.

Esto es especialmente útil para desacoplar cosas. Los marcos de GUI no serían posibles sin ese concepto, porque un Button simplemente no puede saber nada sobre el programa en el que va a usarlo, por lo que no puede llamar a sus métodos por sí solo cada vez que se hace clic. En su lugar, debe indicarle a qué métodos debe llamar cuando se hace clic.

Supongo que está familiarizado con los eventos y los usa con regularidad. Un campo event es en realidad una lista de dichos delegados (también llamado delegado de multidifusión). Tal vez las cosas serán más claras cuando nos fijamos en cómo podríamos "simular" eventos en C# si no tuviera la palabra clave event, pero sólo (no-multicast) delegados:

public class Button : Rectangle 
{ 
    private List<Delegate> _delegatesToNotifyForClick = new List<Delegate>(); 

    public void PleaseNotifyMeWhenClicked(Delegate d) 
    { 
     this._delegatesToNotifyForClick.Add(d); 
    } 

    // ... 

    protected void GuiEngineToldMeSomeoneClickedMouseButtonInsideOfMyRectangle() 
    { 
     foreach (Delegate d in this._delegatesToNotifyForClick) 
     { 
      d.Invoke(this, this._someArgument); 
     } 
    } 
} 

// Then use that button in your form 

public class MyForm : Form 
{ 
    public MyForm() 
    { 
     Button myButton = new Button(); 
     myButton.PleaseNotifyMeWhenClicked(new Delegate(this.ShowMessage)); 
    } 

    private void ShowMessage() 
    { 
     MessageBox.Show("I know that the button was clicked! :))))"); 
    } 
} 

Espero que podría ayudar un poco . ;-)

4

Este artículo de Chris Sells podría ayudar:

.NET Delegates: A C# Bedtime Story

+0

+1. Pienso en los delegados como interfaces de método único. "Entonces, decidió separar los métodos de la interfaz en funciones de delegado separadas, cada una de las cuales actuaba como una pequeña interfaz de un método cada una" – kenny

+0

Otro gran ejemplo, gracias. – Kin

-1

Yo no creo que nadie ha mencionado, pero la sección sobre los delegados de Jon Skeet en su libro "C# in depth" es probablemente el lo mejor que he encontrado Al igual que el OP, solía tener problemas con los delegados. Lo que solía tener problema era configurar los delegados.

El libro de Jon Skeet es excelente para explicar a los delegados porque desglosa la "configuración" del delegado, hace aclaraciones entre el tipo de delegado y la instancia delegada (tendrá que tener el libro para darle sentido; Podría estar abriéndome a la infracción de derechos de autor ya que no podría explicarlo mejor que Jon). Lo mejor de todo es que proporciona un pequeño pero claro ejemplo.

No estoy de ninguna manera afiliada con Jon Skeet o Manning, pero vale la pena leerla y no solo para la sección sobre delegados.

1

¡Vamos chicos! ¡Todos ustedes complicaron con éxito a los DELEGADOS :)!

Trataré de dejar una pista aquí: entendí a los delegados una vez que me di cuenta de las llamadas a jquery ajax en Javascript. por ejemplo: ajax.send (url, data, successcallback, failcallback) es la firma de la función. como usted sabe, envía datos a la URL del servidor, como respuesta, podría ser 200OK o algún otro error. En caso de tal evento (éxito/falla), desea ejecutar una función. Por lo tanto, esto actúa como un marcador de posición de una función, para poder mencionar en éxito o fracaso. Ese marcador de posición puede no ser muy genérico: puede aceptar un conjunto de parámetros y puede/no devolver el valor. ¡Esa declaración de dicho marcador de posición, si se hace en C# SE LLAMA DELEGADO! Como las funciones de JavaScript no son estrictas con el número de argumentos, simplemente las verías como marcadores de posición GENERIC ... pero C# tiene algunas declaraciones ESTRICTAS ... ¡que se reduce a DELEGAR declaraciones!

Espero que ayude!

0

Delegado es un tipo de función de seguridad puntero, lo que significa puntos de delegado a una función cuando se invoca la función delegado la función real será invocado. Se usa principalmente al desarrollar el marco de aplicación principal. Cuando queremos desacoplar la lógica, podemos usar delegar. Es decir, en lugar de la lógica de codificación manual en un método particular, podemos pasar el delegado a la función y establecer lógica de función diferente dentro de la función de delegado. Los delegados agregan flexibilidad a su marco.

Ejemplo: cómo usarlo

class program { 
public static void Main) { 
    List<Employee> empList = new List<Employee>() { 
    new Employee() {Name = "Test1", Experience = 6 }, 
    new Employee() {Name = "Test2", Experience = 2 }, 
    } 

// delegate point to the actual function 
IsPromotable isEligibleToPromote = new IsPromotable(IsEligibleToPromoteEmployee) 
Employee emp = new Employee(); 

// pass the delegate to a method where the delegate will be invoked. 
emp.PromoteEmployee(empList, isEligibleToPromote); 

// same can be achieved using lambda empression no need to declare delegate 
emp.PromoteEmployee (empList, emply =>emply.Experience > 2); 

    // this condition can change at calling end 
    public static bool IsEligibleToPromoteEmployee (emp){ 
     if (emp.Experience > 5) 
     return true; 
     else 
     return false; 
    } 
    } 
} 


public delegate bool IsPromotable(Employee emp); 

public class Employee { 
    public string Name {get; set;} 
    public int Experience {get; set;} 

    // conditions changes it can 5, 6 years to promote 
    public void PromoteEmployee (List<Employee> employees, IsPromotable isEligibleToPromote) { 
    foreach (var employee in employees) { 
    // invoke actual function 
    if (isEligibleToPromote(employee)){ 
     Console.WriteLine("Promoted"); 
    } 
    } 
} 
Cuestiones relacionadas