Uso en el mundo real de los delegados de C # [cerrado]


16

Creo que conceptualmente entiendo a los delegados de C #, sin embargo, estoy luchando por encontrar un ejemplo del mundo real donde puedan ser útiles. ¿Puede proporcionar algunas respuestas que detallen cómo se utilizaron los delegados de C # en aplicaciones reales y qué problemas le permitieron solucionar?


2
Casi todas las clases en .NET Framework exponen algún conjunto de eventos, así que ahí lo tienes. Es solo una forma de encapsular alguna unidad de trabajo. Por ejemplo, supongamos que estaba implementando una estructura de árbol binario genérico en C. Bueno, la única forma de ordenar su árbol sería tomar como parámetro un puntero de función que supiera cómo ordenar.
Ed S.

Respuestas:


16

El código GUI usa delegados para manejar eventos, como clics de botones, movimientos de ventanas. Usar el delegado le permite tener una función llamada cada vez que ocurre el evento. Un ejemplo sería vincular una función que guarda datos a un botón "Guardar" en la interfaz. Cuando se hace clic en el botón, está configurado para ejecutar la función que guarda los datos. Es útil en la programación de la GUI porque todo su programa podría estar esperando que el usuario haga algo y usted no tiene forma de saber qué hará primero. El uso de delegados permite que la funcionalidad de su programa se conecte a la interfaz de usuario de tal manera que el usuario pueda hacer las cosas de la forma que desee.


2
++ Tienes razón, pero todavía lo odio :-) así que hace mucho tiempo se me ocurrió esto .
Mike Dunlavey

12

Linq usa Func<T>y Action<T>delega por todo el lugar como parámetros.

Estos le permiten usar expresiones lambda como parámetros y definen la acción a tomar como parte de la lista de parámetros.


12

Prácticamente cualquier cosa que use el Patrón de Observador probablemente implementaría delegados.

Lea la descripción y probablemente imaginará algunos escenarios en los que los usaría. El manejo de eventos GUI es un ejemplo común.


+1, El patrón de estrategia es realmente donde brillan los delegados, es decir, tienes alguna clase en la que algún método hace algo, pero quieres que algo sea intercambiable y sin dependencia directa, ergo delegados. Tenga en cuenta que los eventos satisfacen un poco la misma necesidad que los delegados, la diferencia es que usted usa delegados cuando necesita reaccionar sobre algún valor de retorno, mientras que solo dispara eventos y lo que sea que sea.
Homde

9

Los delegados son muy útiles en la programación asincrónica.

Tienes una clase que hace cosas de forma asincrónica y tiene una devolución de llamada. Puede hacer que se invoque el método delegado al devolver la llamada, y la implementación de su clase hará la lógica descrita en su método delegado.


9

Los delegados son particularmente útiles como una solución para el agujero en el patrón del medio . Esencialmente, hay muchos casos en los que desea incluir un conjunto único de instrucciones dentro de un conjunto común de instrucciones. Es particularmente difícil si las instrucciones antes y después del bit único necesitan compartir el estado. Con los delegados, puede pasar un delegado a una función. La función ejecuta el bit anterior, ejecuta el delegado y luego ejecuta el bit posterior.


5

En los "viejos tiempos" de los lenguajes que no son OOP como Fortran y C, fue increíblemente útil poder hacer que una subrutina recibiera un argumento que apuntaba a una función. Por ejemplo, la qsortfunción funciona con una función de comparación proporcionada por el usuario. Existen numerosas subrutinas para resolver ecuaciones diferenciales ordinarias o para optimizar funciones, y todas toman punteros de función como argumentos.

En los sistemas de ventanas, todo tipo de devoluciones de llamada siguen el mismo patrón.

En Lisp, incluso en los primeros días, había algo llamado un "argumento funcional" o FUNARG, que no solo era una función, sino que también contenía un contexto de almacenamiento donde podía recordar e interactuar con parte del mundo exterior.

Esta misma necesidad existe en los lenguajes OOP, excepto cuando pasa la dirección de una función, también tiene que pasar la dirección del objeto de la cual la función es un método. Eso son dos cosas que tienes que pasar. Entonces, un delegado es solo eso, y permite que se siga utilizando ese buen patrón antiguo.


3

Aquí hay un ejemplo simple que muestra cuán útiles pueden ser los delegados para crear código simple que siga el principio DRY. También le permite mantener el código extremadamente cerca de donde se necesita.

Action<Button, Action<Button>> prepareButton = 
    (btn, nxt) => { 
        btn.Height = 32;
        btn.Width= 64;
        nxt(btn);
    };

prepareButton(myBtn1, btn => btn.Text = "A");
prepareButton(myBtn2, btn => btn.Text = "B");
prepareButton(myBtn3, btn => btn.Text = "C");

Aquí hay un ejemplo del mundo real de la ventaja que brindan los delegados.

protected override void PageInitialize()
{
    const string selectCodeFormat = "javascript:selectCode('{0}', '{1}');";
    const string onClick = "return toggleElement(this);";

    Func<HtmlGenericControl> getElement = null;
    Action<HtmlGenericControl> setElement = null, addChild = null;
    HtmlGenericControl level1Element = null, level2Element = null, level3Element = null, level4Element = null;
    string className = null, code = null, description = null;           

    using (var records = Core.Database.ExecuteRecords("code.SocCodeTree"))
    {
        while (records.Read())
        {
            code = records.GetString("Code");
            description = records.GetString("Description"); 

            if (records.GetString("Level4") != "")
            {
                className = "Level4";
                setElement = e => level4Element = e;
                getElement = () => level4Element;
                addChild = e => level3Element.Controls.Add(e);
            }
            else if (records.GetString("Level3") != "")
            {
                className = "Level3";
                setElement = e => level3Element = e;
                getElement = () => level3Element;
                addChild = e => level2Element.Controls.Add(e);
            }
            else if (records.GetString("Level2") != "")
            {
                className = "Level2";
                setElement = e => level2Element = e;
                getElement = () => level2Element;
                addChild = e => level1Element.Controls.Add(e);
            }
            else
            {
                className = "Level1";
                setElement = e => level1Element = e;
                getElement = () => level1Element;
                addChild = e => Root.Controls.Add(e);
            }

            var child = new HtmlGenericControl("li");
            child.Attributes["class"] = className;
            var span = new HtmlGenericControl("span") { 
                InnerText = code + " - " + description + " - " 
            };
            span.Attributes["onclick"] = onClick;
            child.Controls.Add(span);
            var a = new HtmlAnchor() { 
                InnerText = "Select", 
                HRef = string.Format(selectCodeFormat, code, description) 
            };
            child.Controls.Add(a);
            setElement(new HtmlGenericControl("ul"));
            child.Controls.Add(getElement());
            addChild(child);    
        }
    }
}

2

Mi primer encuentro con los delegados fue buscar una actualización del programa (formularios Windows C # 3.5) descargando un archivo de mi sitio web, pero para evitar que la actualización verificara el bloqueo de todo el programa, utilicé un delegado y un hilo para hacerlo de forma asincrónica.


1

He visto implementaciones interesantes del patrón de estrategia que usa delegados de manera efectiva. (es decir, la estrategia es un delegado)

El que estaba buscando era para encontrar rutas donde el algoritmo para encontrar la ruta era un delegado que podía (re) asignarse en tiempo de ejecución para que se pudieran usar diferentes algoritmos (BFS vs A * etc.)


1

Muchos de los patrones clásicos de GoF se pueden implementar con delegados: por ejemplo, el patrón de comando, el patrón de visitante, el patrón de estrategia, el patrón de fábrica y el patrón de observador a menudo se pueden implementar con un delegado simple. A veces, una clase es mejor (por ejemplo, cuando un comando necesita un nombre o un objeto de estrategia necesita ser serializado), pero en la mayoría de los casos, usar Action<...>o Func<...>es mucho más elegante que crear una interfaz dedicada de un método.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.