ventajas usar tipo runtimebinderexception runtimebinder que puede porque por microsoft invocar hilos funcion delegate delegados delegado csharp c# .net delegates

tipo - porque usar delegate c#



¿Cuándo y por qué usar delegados? (8)

Descripción de los delegados

Los delegados tienen las siguientes propiedades:

  • Los delegados son similares a los punteros de función de C ++, pero son de tipo seguro.
  • Los delegados permiten que los métodos se pasen como parámetros.
  • Los delegados se pueden utilizar para definir los métodos de devolución de llamada.
  • Los delegados pueden ser encadenados juntos; por ejemplo, se pueden llamar múltiples métodos en un solo evento.
  • Los métodos no necesitan coincidir exactamente con la firma del delegado. Para obtener más información, consulte Variación de covarianza y contra.
  • C # versión 2.0 introduce el concepto de Métodos anónimos, que permite que los bloques de código se pasen como parámetros en lugar de un método definido por separado.

Esta pregunta ya tiene una respuesta aquí:

Soy relativamente nuevo en C #, y me pregunto cuándo usar adecuadamente a los delegados . se usan ampliamente en la declaración de eventos, pero ¿cuándo debo usarlos en mi propio código y por qué son útiles? ¿Por qué no usar otra cosa?

También me pregunto cuándo debo usar delegados y no tengo otra alternativa .

¡Gracias por la ayuda!

EDITAR: Creo que he encontrado un uso necesario de los delegados here


Acabo de repasar esto, así que compartiré un ejemplo, ya que usted ya tiene descripciones, pero en este momento una de las ventajas que veo es evitar las advertencias de estilo de referencia circular donde no puede haber 2 proyectos que hagan referencia a cada uno. otro.

Supongamos que una aplicación descarga un XML y luego guarda el XML en una base de datos.

Tengo 2 proyectos aquí que construyen mi solución: FTP y SaveDatabase.

Entonces, nuestra aplicación comienza buscando descargas y descargando los archivos y luego llama al proyecto SaveDatabase.

Ahora, nuestra aplicación debe notificar al sitio FTP cuando se guarda un archivo en la base de datos cargando un archivo con datos Meta (ignore por qué, es una solicitud del propietario del sitio FTP). El problema es ¿en qué punto y cómo? Necesitamos un nuevo método llamado NotifyFtpComplete () pero, ¿en cuál de nuestros proyectos debería guardarse también - FTP o SaveDatabase? Lógicamente, el código debe vivir en nuestro proyecto FTP. Pero, esto significaría que nuestro NotifyFtpComplete tendrá que ser activado o, tendrá que esperar hasta que se complete el proceso de guardar, y luego consultar la base de datos para asegurarse de que esté allí. Lo que debemos hacer es decirle a nuestro proyecto SaveDatabase que llame directamente al método NotifyFtpComplete () pero no podemos; obtendríamos una referencia circular y NotifyFtpComplete () es un método privado. Qué pena, esto hubiera funcionado. Bueno, puede.

Durante el código de nuestra aplicación, habríamos pasado parámetros entre los métodos, pero ¿qué pasaría si uno de esos parámetros fuera el método NotifyFtpComplete? Sí, pasamos el método, con todo el código dentro también. Esto significaría que podríamos ejecutar el método en cualquier momento, desde cualquier proyecto. Bueno, esto es lo que el delegado es. Esto significa que podemos pasar el método NotifyFtpComplete () como un parámetro a nuestra clase SaveDatabase (). En el punto en que guarda, simplemente ejecuta el delegado.

Vea si este ejemplo crudo ayuda (pseudo código). También asumiremos que la aplicación comienza con el método Begin () de la clase FTP.

class FTP { public void Begin() { string filePath = DownloadFileFromFtpAndReturnPathName(); SaveDatabase sd = new SaveDatabase(); sd.Begin(filePath, NotifyFtpComplete()); } private void NotifyFtpComplete() { //Code to send file to FTP site } } class SaveDatabase { private void Begin(string filePath, delegateType NotifyJobComplete()) { SaveToTheDatabase(filePath); //InvokeTheDelegate - here we can execute the NotifyJobComplete method at our preferred moment in the application, despite the method being private and belonging to a different class. NotifyJobComplete.Invoke(); } }

Entonces, con eso explicado, podemos hacerlo de verdad ahora con esta aplicación de consola usando C #

using System; namespace ConsoleApplication1 { //I''ve made this class private to demonstrate that the SaveToDatabase cannot have any knowledge of this Program class. class Program { static void Main(string[] args) { //Note, this NotifyDelegate type is defined in the SaveToDatabase project NotifyDelegate nofityDelegate = new NotifyDelegate(NotifyIfComplete); SaveToDatabase sd = new SaveToDatabase(); sd.Start(nofityDelegate); Console.ReadKey(); } //this is the method which will be delegated - the only thing it has in common with the NofityDelegate is that it takes 0 parameters and that it returns void. However, it is these 2 which are essential. It is really important to notice that it writes a variable which, due to no constructor, has not yet been called (so _notice is not initialized yet). private static void NotifyIfComplete() { Console.WriteLine(_notice); } private static string _notice = "Notified"; } public class SaveToDatabase { public void Start(NotifyDelegate nd) { Console.WriteLine("Yes, I shouldn''t write to the console from here, it''s just to demonstrate the code executed."); Console.WriteLine("SaveToDatabase Complete"); Console.WriteLine(" "); nd.Invoke(); } } public delegate void NotifyDelegate(); }

Le sugiero que pase por el código y vea cuándo se llama a _notice y cuándo se llama al método (delegate), espero que las cosas queden muy claras.

Sin embargo, por último, podemos hacerlo más útil cambiando el tipo de delegado para incluir un parámetro.

using System.Text; namespace ConsoleApplication1 { //I''ve made this class private to demonstrate that the SaveToDatabase cannot have any knowledge of this Program class. class Program { static void Main(string[] args) { SaveToDatabase sd = new SaveToDatabase(); //Please note, that although NotifyIfComplete() takes a string parameter, we do not declare it - all we want to do is tell C# where the method is so it can be referenced later - we will pass the paramater later. NotifyDelegateWithMessage nofityDelegateWithMessage = new NotifyDelegateWithMessage(NotifyIfComplete); sd.Start(nofityDelegateWithMessage); Console.ReadKey(); } private static void NotifyIfComplete(string message) { Console.WriteLine(message); } } public class SaveToDatabase { public void Start(NotifyDelegateWithMessage nd) { //To simulate a saving fail or success, I''m just going to check the current time (well, the seconds) and store the value as variable. string message = string.Empty; if (DateTime.Now.Second > 30) message = "Saved"; else message = "Failed"; //It is at this point we pass the parameter to our method. nd.Invoke(message); } } public delegate void NotifyDelegateWithMessage(string message); }


Considero a los delegados como interfaces anónimas . En muchos casos, puede usarlos siempre que necesite una interfaz con un solo método, pero no desea la sobrecarga de definir esa interfaz.


Digamos que desea escribir un procedimiento para integrar alguna función de valores reales f ( x ) en algún intervalo [a, b]. Digamos que queremos usar el método gaussiano de 3 puntos para hacer esto (cualquiera lo hará, por supuesto).

Idealmente queremos alguna función que se vea como:

// ''f'' is the integrand we want to integrate over [a, b] with ''n'' subintervals. static double Gauss3(Integrand f, double a, double b, int n) { double res = 0; // compute result // ... return res; }

Así que podemos pasar cualquier Integrand , f , y obtener su integral definida en el intervalo cerrado.

¿De qué tipo debería ser Integrand ?

Sin delegados

Bueno, sin delegados, necesitaríamos algún tipo de interfaz con un solo método, por ejemplo, eval declara lo siguiente:

// Interface describing real-valued functions of one variable. interface Integrand { double eval(double x); }

Entonces necesitaríamos crear un montón de clases implementando esta interfaz, de la siguiente manera:

// Some function class MyFunc1 : Integrand { public double eval(double x) { return /* some_result */ ; } } // Some other function class MyFunc2 : Integrand { public double eval(double x) { return /* some_result */ ; } } // etc

Luego, para usarlos en nuestro método Gauss3, necesitamos invocarlo de la siguiente manera:

double res1 = Gauss3(new MyFunc1(), -1, 1, 16); double res2 = Gauss3(new MyFunc2(), 0, Math.PI, 16);

Y Gauss3 necesita hacer el siguiente aspecto:

static double Gauss3(Integrand f, double a, double b, int n) { // Use the integrand passed in: f.eval(x); }

Así que tenemos que hacer todo eso para usar nuestras funciones arbitrarias en Guass3 .

Con delegados

public delegate double Integrand(double x);

Ahora podemos definir algunas funciones estáticas (o no) que se adhieren a ese prototipo:

class Program { public delegate double Integrand(double x); // Define implementations to above delegate // with similar input and output types static double MyFunc1(double x) { /* ... */ } static double MyFunc2(double x) { /* ... */ } // ... etc ... public static double Gauss3(Integrand f, ...) { // Now just call the function naturally, no f.eval() stuff. double a = f(x); // ... } // Let''s use it static void Main() { // Just pass the function in naturally (well, its reference). double res = Gauss3(MyFunc1, a, b, n); double res = Gauss3(MyFunc2, a, b, n); } }

No hay interfaces, no hay cosas maliciosas .eval, no hay creación de instancias de objetos, solo un simple uso de puntero de función, para una tarea simple.

Por supuesto, los delegados son más que simples punteros de función bajo el capó, pero eso es un problema separado (encadenamiento de funciones y eventos).


Estoy de acuerdo con todo lo que ya se ha dicho, solo trato de poner algunas otras palabras en él.

Un delegado puede ser visto como un marcador de posición para un / algunos método (s).

Al definir a un delegado, le está diciendo al usuario de su clase: " Por favor, siéntase libre de asignar cualquier método que coincida con esta firma, al delegado y será llamado cada vez que se llame a mi delegado ".

El uso típico es, por supuesto, los eventos. Todo el delegado de OnEventX a los métodos que el usuario define.

Los delegados son útiles para ofrecer al usuario de sus objetos alguna capacidad para personalizar su comportamiento. La mayoría de las veces, puedes usar otras formas para lograr el mismo propósito y no creo que puedas ser forzado a crear delegados. Es solo la forma más fácil en algunas situaciones de hacer las cosas.


Los delegados son extremadamente útiles cuando desean declarar un bloque de código que desea pasar. Por ejemplo, cuando se utiliza un mecanismo genérico de reintento.

Seudo:

function Retry(Delegate func, int numberOfTimes) try { func.Invoke(); } catch { if(numberOfTimes blabla) func.Invoke(); etc. etc. }

O cuando quiere hacer una evaluación tardía de los bloques de código, como una función en la que tiene alguna acción Transform , y desea tener una BeforeTransform y AfterTransform que pueda evaluar dentro de su función Transform, sin tener que saber si el BeginTransform está completo , o lo que tiene que transformar.

Y por supuesto al crear manejadores de eventos. No desea evaluar el código ahora, sino solo cuando sea necesario, por lo que registra un delegado que puede invocarse cuando se produce el evento.


Un delegado es una clase simple que se utiliza para apuntar a métodos con una firma específica, convirtiéndose esencialmente en un puntero de función de tipo seguro. El propósito de un delegado es facilitar una llamada a otro método (o métodos), una vez que se haya completado, de manera estructurada.

Si bien podría ser posible crear un extenso conjunto de código para realizar esta funcionalidad, no es necesario que lo haga. Puede utilizar un delegado.

Crear un delegado es fácil de hacer. Identifique la clase como un delegado con la palabra clave "delegar". Luego especifique la firma del tipo.


Un delegado es una referencia a un método. Mientras que los objetos pueden enviarse fácilmente como parámetros a métodos, constructores o lo que sea, los métodos son un poco más complicados. Pero de vez en cuando es posible que sientas la necesidad de enviar un método como parámetro a otro método, y ahí es cuando necesitarás delegados.

using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyLibrary; namespace DelegateApp { /// <summary> /// A class to define a person /// </summary> public class Person { public string Name { get; set; } public int Age { get; set; } } class Program { //Our delegate public delegate bool FilterDelegate(Person p); static void Main(string[] args) { //Create 4 Person objects Person p1 = new Person() { Name = "John", Age = 41 }; Person p2 = new Person() { Name = "Jane", Age = 69 }; Person p3 = new Person() { Name = "Jake", Age = 12 }; Person p4 = new Person() { Name = "Jessie", Age = 25 }; //Create a list of Person objects and fill it List<Person> people = new List<Person>() { p1, p2, p3, p4 }; //Invoke DisplayPeople using appropriate delegate DisplayPeople("Children:", people, IsChild); DisplayPeople("Adults:", people, IsAdult); DisplayPeople("Seniors:", people, IsSenior); Console.Read(); } /// <summary> /// A method to filter out the people you need /// </summary> /// <param name="people">A list of people</param> /// <param name="filter">A filter</param> /// <returns>A filtered list</returns> static void DisplayPeople(string title, List<Person> people, FilterDelegate filter) { Console.WriteLine(title); foreach (Person p in people) { if (filter(p)) { Console.WriteLine("{0}, {1} years old", p.Name, p.Age); } } Console.Write("/n/n"); } //==========FILTERS=================== static bool IsChild(Person p) { return p.Age < 18; } static bool IsAdult(Person p) { return p.Age >= 18; } static bool IsSenior(Person p) { return p.Age >= 65; } } }