sábado, 11 de noviembre de 2017

Curso de C#: delegados

Conceptos teóricos


Un delegado es una referencia a una función, también se conoce como un puntero a una función. Un delegado permite acceder a una función de forma casi anónima, ya que simplemente tiene la dirección de memoria de dicha función. Y sabiendo la dirección de la memoria, podemos acceder a ella.
El equivalente de los delegados en el lenguaje C/C++ sería un puntero a función (callback)

Un delegado, es un tipo que define una firma o prototipo de método y se puede asociar a cualquier método con una firma compatible. Puede invocar (o llamar) al método a través del delegado. Un delegado permite enviar un método como parámetro a otro método.

Curso de C#. Delegados

Firma o prototipo de método

Cuando se habla de una "firma o prototipo de método" se hace referencia al tipo de retorno, número y tipos de parámetros del mismo. A continuación se muestra un ejemplo de dos firmas diferentes de un método:
Public void MostrarTexto(string mensaje, int cantidadveces) {…}
Public string MostrarTexto(string mensaje) {…}
Son diferentes, porque el tipo de dato que retorna, la cantidad de parámetros y los tipos de parámetros son diferentes para cada método.
Una “firma o prototipo compatible" significa que el delegado debe tener la misma firma del método que va a invocar (llamar o implementar).

Declaración de un delegado

Un delegado se declara igual que la firma de un método, sin cuerpo, es decir sin llaves e interponiendo la palabra reservada delegate entre el modificador de acceso y el tipo de retorno de la firma.

Public delegate void DelegadoMostrar(string mensaje, int cantidadveces);

Cada delegado debe tener un nombre diferente. Una vez declarados los delegados y los métodos podemos instanciarlos e invocarlos.

Utilización de los delegados


Si queremos acceder a una función que devuelve una cadena y que recibe un parámetro de tipo Cliente, debemos definir un delegado con esas características, y cuando posteriormente queramos acceder a ese método, en lugar de hacerlo directamente o por medio de un puntero directo, usaremos un objeto del tipo definido por el delegado. Lo que nos lleva a una segunda definición de lo Un delegado permite acceder a una función de forma casi anónima, ya que simplemente tiene la dirección de memoria de dicha función .que es un delegado, en la que podemos decir que es un tipo especial que nos permite definir la forma de acceder a una función.

Veamos el ejemplo del método que devuelve una cadena y recibe un  parámetro de tipo Cliente. Ese método lo podemos definir en C# de esta forma:

public string MiFuncion(Cliente c)
{return ...;}

La forma de usar ese método sería algo así:

string s = MiFuncion( new Cliente() );


Los delegados, y los eventos en .NET están estrechamente relacionados; tanto es así que no podemos definir un evento sin la intervención de un delegado.

Para utilizar un delegado es necesario crear una instancia de él, indicándole el nombre del método que ejecutará; así:
DelegadoMostrar miDelegado = new DelegadoMostrar(MostrarTexto);
Al constructor del delegado se le envía el nombre (solo el nombre, sin parámetros) del método que se invocará.
Después se invoca el delegado:

miDelegado(“hola mundo”, 5);

Al llamar al delegado se invoca el método que se dio como parámetro al instanciarlo. No se llama el método directamente porque, con un delegado se puede invocar cualquier método con la única condición de que la firma sea idéntica. Un ejemplo son los eventos. Cuando se crea un evento onclick a un botón lo que hace es crear un método, y "decirle" al botón que cuando hagan clic en él, invoque dicho método.
Un tipo delegado es el que se define con la palabra clave delegate.
Un objeto delegado es una instancia de ese tipo delegado.


Ejemplo mínimo de declaración y utilización de delegados:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Delegados
{

// Un delegado puede estar dentro de una clase, fuera de una clase, dentro de un namespace o fuera de un namespace.
// Se crea y define el -tipo- delegado, en la definición (o firma) de un tipo delegado
// Se considera: el tipo de retorno, número de parámetros y el tipo de los parámetros, estas características las deben cumplir los métodos que luego se asignarán.

public delegate int MiDelegado(int parámetro);  // Es muy similar a declarar un método
    class ClsDelegados
    {
      
            public static void Main()
            {
                Console.WriteLine("Se inicia el programa");

                // Se crea un objeto de la clase 'OtraClase'
                OtraClase objOtraClase = new OtraClase();

  // Se crea un objeto delegado y se le asigna un método, en este ejemplo se
  // asigna solo un método, pero se le pueden asignar más.
  // Crear un objeto delegado es muy similar a crear un objeto con una clase, la
  // diferencia es que le asignamos un método.
  // El método no se llama usando '()' solo se le asigna al objeto delegado, por    
  //eso no se usan los '()'
                MiDelegado objDelegado = new MiDelegado(objOtraClase.Método1);

  // Se crea una variable de tipo int y se le asigna el valor de retorno
  // del objeto delegado, que es el mismo retorno del método anteriormente asignado
                int retorno = objDelegado(5); // Se hace la llamada de la misma forma que un método

                // Muestra el valor de retorno
                Console.WriteLine("El valor devuelto es {0}", retorno);
            }
        }

        public class OtraClase
        {
 // Este método cumple con el prototipo del delegado al cual se asigna
            public int Método1(int a)
            {
                Console.WriteLine("Soy Método1 y mi argumento es: {0}", a);
                return a + 10;
            }
        }
    }

Al compilar y ejecutar el programa, la salida será de este estilo:

Se inicia el programa
Soy el método1 y mi argumento es: 5
El valor devuelto es 15

Añadir y quitar métodos a un objeto delegado


Se puede añadir uno o más métodos a un objeto delegado y en el caso de ser varios métodos es posible ejecutar de forma ordenada a través del objeto, añadir y eliminar métodos a un objeto delegado y ejecutarlos de forma ordenada.

Se utilizan los operadores ‘+=’ para añadir y ‘-=’ para eliminar métodos. Estos son operadores sobrecargados para que el uso de los objetos delegados sea más intuitivo.
using System;

public class Delegado
{
// Se crea y define un tipo delegado,
// Se define el tipo delegado, tipo de retorno, numero de parámetros y tipos de parámetros.

    public delegate void TipoDelegado();

    public static void Main()
    {
        Console.WriteLine("Se inicia el programa");

        // Se crea un objeto de la clase Delegado
        Delegado objClaseDelegado = new Delegado();

// Se crea un objeto de tipo delegado y se le añade un método. //No importa si el método es de un objeto de la propia clase TipoDelegado objTipoDelegado = new TipoDelegado(objClaseDelegado.Método1);

// Se añade al objeto delegado un método, ahora el objeto delegado tendrá 2 métodos añadidos.
// Al añadir un primer método a un delegado se puede usar el operador de asignación '='
// Para añadir otro método se tiene que usar el operador '+='
        objTipoDelegado += new TipoDelegado(objClaseDelegado.Método2);

        Console.WriteLine("Se llamará al objeto delegado con los métodos ya asignados");
        objTipoDelegado();

        Console.WriteLine("Se llamará al objeto delegado después de eliminar Método2");
//Eliminar el método 'Método2' y luego llamar al objeto delegado
        objTipoDelegado -= new TipoDelegado(objClaseDelegado.Método2);
        objTipoDelegado();

 // Es posible añadir el mismo método más de una vez
        Console.WriteLine("Se añade -de nuevo- Método1");
        objTipoDelegado += new TipoDelegado(objClaseDelegado.Método1);
        objTipoDelegado();
    }

    // Los métodos deben cumplir con la definición (firma) del tipo delegado (void en este caso)
    public void Metodo1()
    {
        Console.WriteLine("Soy el Método1");
    }

    public void Metodo2()
    {
        Console.WriteLine("Soy el Método2");
    }
}

Al ejecutar el programa el resultado será:

Se inicia el programa
Soy el Método1
Soy el Método2
Se llamará al objeto delegado después de quitar Método2
Soy el Método1
Se añade -de nuevo- el Método1
Soy el Método1
Soy el Método1

Al inicializar un objeto delegado, se le puede asignar un método usando el operador ‘=’ , pero para asignar o quitar otros métodos al objeto delegado se tiene que usar los operadores ‘+=’ y ‘-=’.

Al llamar al objeto delegado se ejecutan los métodos que almacena de forma ordenada, salen en el mismo orden que se añadieron.

Un mismo método se puede añadir a un objeto delegado más de una vez.

Cuándo utilizar delegados


Los delegados se pueden utilizar en los siguientes supuestos:
-Cuando se llama a varios métodos con una sola llamada.

-Cuando se pasan métodos como parámetros. 

-Para la ordenación de un conjunto de elementos. Por ejemplo, para ordenar una secuencia de métodos.

-Cuando se utiliza un modelo de diseño de eventos. Los eventos son como las propiedades, son una forma de acceder a los delegados. Devuelven una respuesta cuando se asigna y/o quita un método a un evento que representa un objeto delegado.

-Para encapsular un método estático. La llamada a un objeto delegado se utiliza para  acceder a métodos estáticos o privados de otra clase.

-El autor de la llamada no tiene necesidad de obtener acceso a otras propiedades, métodos o interfaces del objeto.

-Cuando una clase necesita más de una implementación de métodos.

-Para realizar devolución de llamadas asíncronas (en un hilo de ejecución aparte) y finalizar llamadas asíncronas.

-Cuando se produce un cambio en base de datos. Por ejemplo, a partir de un cambio ‘x’ en una tabla, se genera una respuesta ‘y’.

-Asociación de código a la carga y descarga de ensamblados.

-Cuando se produce un cambio en el sistema de archivos. Al borrar ‘x’ archivo se escribe un registro en otro archivo ‘y’, que contiene datos del archivo borrado.

A continuación extendemos uno de los casos presentados en la lista anterior.

Acceso a miembros de delegados


A continuación veremos cómo acceder a métodos privados y estáticos de otra clase utilizando delegados. 

//  Accede a varios métodos estáticos y privados


using System;

public class EstaClase
{
    public delegate void MiDelegado(int parametro1, int parametro2);

    public static void Main()
    {
        Console.WriteLine("Se inicia el programa");

// Se crea una instancia de la clase OtraClase'
        OtraClase objOtraClase = new OtraClase();

        Console.WriteLine("Se añade al objeto delegado el método estático 'Método1DeOtraClase'");
// Añadir a 'objDelegado' un método estático de 'OtraClase'
// Para añadir un primer método a un objeto delegado, se usa el operador '='.
        Console.WriteLine("Se crea una instancia de la clase 'OtraClase'");
        MiDelegado objDelegado = new MiDelegado(OtraClase.Metodo1DeOtraClase);

        Console.WriteLine("Se añade al objeto delegado el método no estático 'Metodo2DeOtraClase'");
// Se añade 'Metodo2DeOtraClase' que no es estático. Ahora se
// Utiliza el operador '+=' ya que no es el primer método a añadir.
        objDelegado += new MiDelegado(objOtraClase.Metodo2DeOtraClase);

        Console.WriteLine("Se añade al objeto delegado el método estático 'Método1DeEstaClase'");
// Se añade un método estático de esta clase. No hay que referirse al nombre de esta
        objDelegado += new MiDelegado(Metodo1DeEstaClase);

        Console.WriteLine("Se crea una instancia de la clase 'EstaClase'");
        // Crear una instancia de esta clase 'EstaClase'
        EstaClase objEstaClase = new EstaClase();

        Console.WriteLine("Se añade al objeto delegado el método no estático 'Método2DeEstaClase'");
        // Se añade un método público de esta clase
        objDelegado += new MiDelegado(objEstaClase.Metodo2DeEstaClase);

        Console.WriteLine("Se llama a objDelegado objDelegado (8, 3);");
// Llamar a un método estático que se almacena en 'objDelegado'
        objDelegado(8, 3);

// Llamamos a los métodos que están relacionados con los métodos // de 'objEstaClase' y los de 'objOtraClase'. Se vio que al llamar // a 'objDelegado' no importa si los métodos a añadir son //estáticos o públicos.

    // Algunos atajos para añadir métodos a un objeto delegado.
        objDelegado += objEstaClase.Metodo2DeEstaClase;
        objDelegado += OtraClase.Metodo1DeOtraClase;

        objDelegado(10, 20);
    }

    public static void Metodo1DeEstaClase(int parametro1, int parametro2)
    {
        Console.WriteLine("Se llama a un método estático 'Metodo1DeEstaClase' de esta clase");
        Console.WriteLine("Muestra los argumentos: {0} y {1}", parametro1, parametro2);
    }

    public void Metodo2DeEstaClase(int parametro1, int parametro2)
    {
        Console.WriteLine("Se llama a 'Metodo2DeOtraClase' de esta clase");
        Console.WriteLine("Muestra los argumentos: {0} y {1}", parametro1, parametro2);
    }
}

public class OtraClase
{
    public static void Metodo1DeOtraClase(int parametro1, int parametro2)
    {
        Console.WriteLine("Se llama a un método estático 'Metodo1DeOtraClase' de la clase 'OtraClase'");
        Console.WriteLine("Muestra los argumentos: {0} y {1}", parametro1, parametro2);
    }

    public void Metodo2DeOtraClase(int parametro1, int parametro2)
    {
        Console.WriteLine("Se a llamado a 'Metodo2DeOtraClase' de un objeto de la clase OtraClase");
        Console.WriteLine("Muestra estos argumentos: {0} y {1}", parametro1, parametro2);
    }
}


A continuación la salida.
Se inicia el programa
Se añade al objeto delegado el método estático 'Metodo1DeOtraClase'
Se crea una instancia de la clase 'OtraClase'
Se añade al objeto delegado el método no estático 'Metodo2DeOtraClase'
Se añade al objeto delegado el método estático 'Metodo1DeEstaClase'
Se crea una instancia de la clase 'EstaClase'
Se añade al objeto delegado el método no estático 'Metodo2DeEstaClase'
Se llama a objDelegado objDelegado (8, 3);
Se llama a un método estático 'Metodo1DeOtraClase' de la clase 'OtraClase'
Muestra estos argumentos: 8 y 3
Se llama a 'Metodo2DeOtraClase' de un objeto de la clase OtraClase
Muestra estos argumentos: 8 y 3
Se llama a un método estático 'Método1DeEstaClase' de esta clase
Muestra estos argumentos: 8 y 3
Se llama a 'Metodo2DeOtraClase' de esta clase
Muestra estos argumentos: 8 y 3
Se llama a un método estático 'Metodo1DeOtraClase' de la clase 'OtraClase'
Muestra estos argumentos: 10 y 20
Se llama a 'Metodo2DeOtraClase' de un objeto de la clase OtraClase
Muestra estos argumentos: 10 y 20
Se llama a un método estático 'Metodo1DeEstaClase' de esta clase
Muestra estos argumentos: 10 y 20
Se llama a 'Metodo2DeOtraClase' de esta clase
Muestra estos argumentos: 10 y 20
Se llama a 'Metodo2DeOtraClase' de esta clase
Muestra estos argumentos: 10 y 20
Se llama a un metodo estático 'Metodo1DeOtraClase' de la clase 'OtraClase'
Muestra estos argumentos: 10 y 20

Un ejemplo con eventos

Imaginemos un coche acelerando cada vez más. Y que cada vez que acelera el sistema envía un mensaje a una caja negra para registrar su actividad  durante su vida útil. A medida que va acelerando va perdiendo el control y a una cierta velocidad choca. Al final alguien revisa la caja negra, y ahí se desencadenan todos los mensajes que registró durante su vida útil.

Diseño técnico


Utilizar dos clases.
A.   Una para el método Main () y para hacer uso de la clase Coche.
B.   Una clase Coche, que tendrá todo el mecanismo del coche. Un método para acelerar, un delegado para manejar los métodos o lo que pase dentro del vehículo (la caja negra).
C.    
Hacer que se muestre en el monitor lo que pasa en el programa. Que el coche va acelerando en x, y el coche va perdiendo el control a x velocidad, que el coche choca a x velocidad.

Pasar un método personalizado al objeto delegado de la clase Coche que contenga la forma en que el mensaje será mostrado en el monitor (personalizado).

Sugerencias para el programa


En la clase que contiene el Main () tendremos el bucle que hace que el coche acelere y el método personalizado, que queremos pasar al objeto delegado de la clase Coche. El método personalizado deberá contener la forma en que el mensaje será presentado a la supuesta persona que desencadene los eventos.

Se crea una clase Coche, que contiene los siguientes miembros:
public delegate void CocheManejaMotor(string msgParaLlamador);  Se utilizará para guardar o dejar referencia a los métodos a asignar.

private CocheManejaMotor listaDeManejadores; Objeto delegado de la clase Coche

public void RegistraMotorCoche(CocheManejaMotor metodoALlamar)
    { listaDeManejadores = metodoALlamar; }

Método a través del cual se puede enviar un objeto delegado del tipo CocheManejaMotor  que proporciona esta clase. Para enviar los mensajes que incluye el objeto delegado.

    public void Acelerar(int delta)  delta es la velocidad que va a aumentar.

Como utilizar delegados para facilitar el uso de eventos


//   Ejemplo que muestra cómo utilizar delegados para facilitar el
//   uso de eventos.

using System;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("***** Delegados para facilitar eventos *****\n");

        // Crea un objeto de la clase Coche.
        Coche coche1 = new Coche(100, 10);

        // Hay que decirle al objeto "coche1" cual es el método a llamar (OnEventoMotorCoche)
        // cuando se nos envíe un mensaje o notificación. Debe cumplir con la firma.
        coche1.RegistraMotorCoche(new Coche.CocheManejaMotor(OnEventoMotorCoche));

        // Acelerar (este es el punto de partida para luego recibir eventos o
        // mensajes). (el bucle for no tiene llaves por que tiene una sola linea)
        Console.WriteLine("***** acelerar *****");
        for (int i = 0; i < 6; i++)
            coche1.Acelerar(20);

        Console.ReadLine();
    }

    // Este es el método personalizado que le enviaremos al objeto delegado.
    public static void OnEventoMotorCoche(string msg)
    {
        Console.WriteLine("\n****** mensaje desde el objeto coche1 *****");
        Console.WriteLine("=> {0}", msg);
        Console.WriteLine("************************************\n");
    }
}

public class Coche
{
    // 1) Definir un tipo delegado.
    public delegate void CocheManejaMotor(string msgParaLlamador);
    // 2) Definir un objeto delegado miembro de esta clase.
    private CocheManejaMotor listaDeManejadores;
    // 3) Añadir una función registro para el llamador.
    // Se le envía un objeto delegado (el creado con new, anteriormente) y se copia
    // ese objeto delegado al del objeto delegado de esta clase.
    public void RegistraMotorCoche(CocheManejaMotor metodoALlamar)
    { listaDeManejadores = metodoALlamar; }

    // Estados de las variables internas
    public int VelocidadActual { get; set; } // Velocidad actual
    public int VelocidadMaxima { get; set; } // Velocidad máxima

    // El coche ha colisionado?
    private bool cocheColision;

    // Constructores de la clase
    public Coche() { VelocidadMaxima = 100; }
    public Coche(int velMax, int velAct)
    {
        VelocidadActual = velAct;
        VelocidadMaxima = velMax;
    }

    public void Acelerar(int delta)
    {
        // ¿Si, este coche ha colisionado?, enviar el mensaje de que ha colisionado.
        if (cocheColision)
        {
            // ¿Si, el objeto delegado 'listaDeManejadores' no tiene métodos y es null?
            if (listaDeManejadores != null)
                listaDeManejadores("Este coche ha colisionado...");
        }

        else
        {
            VelocidadActual += delta;

            // ¿este coche va a mucha velocidad?
            if (10 == (VelocidadMaxima - VelocidadActual) && listaDeManejadores != null)
                listaDeManejadores("¡cuidado! va a chocar");
            // ¿Si, este coche va a más velocidad del limite o igual velocidad?
            if (VelocidadActual >= VelocidadMaxima)
                cocheColision = true;
            else
                Console.WriteLine("Velocidad = {0}", VelocidadActual);
        }
    }
}

Al ejecutar se obtendrá un resultado de este estilo


VelocidadActual = 30
VelocidadActual = 50
VelocidadActual = 70
¡Cuidado va a chocar!
VelocidadActual = 90
Este coche ha colisionado

Manejar listas de métodos que referencian los objetos delegados


A continuación veremos:

Como manejar las listas de métodos que referencian los objetos delegados para saber sus métodos y su clase.
Combinar 2 objetos delegados (se combinan las listas de métodos que contienen los objetos delegados)
Ejecutar todos los métodos que referencia un objeto delegado.

El siguiente código es un ejemplo teórico que muestra los puntos anteriormente especificados.
using System;
using System.Reflection;

delegate int MiTipoDelegado(int Parámetro);

public class Delegados
{
    public static void Main()
    {
        Console.WriteLine("Se inicia el programa\n");

        OtraClase objOtraClase = new OtraClase();

        // La palabra clave 'delegate' representa una clase sellada
        //  'System.MulticastDelegate', sus intancias pueden ser inicializadas como cualquier
        //  otra clase. Entonces ->
        //  MiTipoDelegado miObjDelegado1 = new MiTipoDelegado (objOtraClase.Método1);
        //  Es lo mismo que -->
        MiTipoDelegado miObjDelegado1 = objOtraClase.Metodo1;

        miObjDelegado1 += objOtraClase.Metodo2;

        MiTipoDelegado miObjDelegado2 = objOtraClase.Metodo3;

        //  Este es el objeto delegado que contendra los métodos de 'miObjDelegado1'
        //  y también los de 'miObjDelegado2'. Es importante asignarle un valor nulo (null)
        MiTipoDelegado miObjDelegado3 = null;

        //  Información sobre los objetos delegados tratados gracias a la clase
        //  'TratarDelegados'
        Console.WriteLine("Mostrar información de 'miObjDelegado1'");
        TratarDelegados.InformaciónObjDelegado(miObjDelegado1);
        Console.WriteLine("\nMostrar información de 'miObjDelegado2'");
        TratarDelegados.InformaciónObjDelegado(miObjDelegado2);
        Console.WriteLine("\nMostrar información de 'miObjDelegado3'");
        TratarDelegados.InformaciónObjDelegado(miObjDelegado3);

        //  Combinar los objetos delegados que contienen métodos, para que los contenga
        //  un solo objeto delegado. Y mostrar información de los objetos delegados.
        Console.WriteLine("\nLuego de combinar los objetos delegados 'miObjDelegado1'");
        Console.WriteLine("y 'miObjDelegado2' en 'miObjDelegado3'");
        miObjDelegado3 += miObjDelegado1 + miObjDelegado2;
        Console.WriteLine("\nMostrar información de 'miObjDelegado3'");
        TratarDelegados.InformaciónObjDelegado(miObjDelegado3);

        //  Llamar a todos los métodos de 'miObjDelegado3'
        Console.WriteLine("\nLlamar a los métodos de 'miObjDelegado3'");
        miObjDelegado3(5);
    }
}

public class OtraClase
{
    public int Metodo1(int a)
    {
        int retorno = a + 10;

        Console.WriteLine("Soy Método1 y mi argumento es: {0} y retorno: {1}",
          a, retorno);

        return retorno;
    }

    public int Metodo2(int a)
    {
        int retorno = a + 20;

        Console.WriteLine("Soy Método2 y mi argumento es: {0} y retorno: {1}",
          a, retorno);

        return retorno;
    }

    public int Metodo3(int a)
    {
        int retorno = a + 30;

        Console.WriteLine("Soy Método3 y mi argumento es: {0} y retorno: {1}",
          a, retorno);

        return retorno;
    }
}

public class TratarDelegados
{

    public static void InformaciónObjDelegado(Delegate objDel)
    {
        Console.WriteLine("Información del objeto delegado");

        if (objDel == null)
        {
            Console.WriteLine("\tEl objeto delegado no referencia a ningún método");
            return;
        }

        foreach (Delegate d in objDel.GetInvocationList())
        {
            Console.WriteLine("\tNombre del método: {0}", d.Method);
            Console.WriteLine("\tNombre de su clase: {0}", d.Target);
        }
    }
}

Al ejecutar muestra esta secuencia:
Se inicia el programa
Mostrar información de 'miObjDelegado1'
Información del objeto delegado
Nombre del método: Int32 Metodo1(Int32)
Nombre de su clase: OtraClase
Nombre del método: Int32 Metodo2(Int32)
Nombre de su clase: OtraClase
Mostrar información de 'miObjDelegado2'
Información del objeto delegado
Nombre del método: Int32 Metodo3(Int32)
Nombre de su clase: OtraClase 
Mostrar información de 'miObjDelegado3'
Información del objeto delegado
El objeto delegado no referencia a ningún método
Luego de combinar los objetos delegados 'miObjDelegado1' y 'miObjDelegado2' en 'miObjDelegado3'
 Mostrar información de 'miObjDelegado3'
Información del objeto delegado
Nombre del método: Int32 Metodo1(Int32)
Nombre de su clase: OtraClase
Nombre del método: Int32 Metodo2(Int32)
Nombre de su clase: OtraClase
Nombre del método: Int32 Metodo3(Int32)
Nombre de su clase: OtraClase
Llamar a los métodos de 'miObjDelegado3'
Soy Método1 y mi argumento es: 5 y retorno: 15
Soy Método2 y mi argumento es: 5 y retorno: 25
Soy Método3 y mi argumento es: 5 y retorno: 35

No hay comentarios:

Publicar un comentario