InicioArticulos y noticiasBases de datosProgramaciónForosInternetServiciosContratacionEmail
Tutorial C#
Introduccion a C#
Programacion con C#
Fundamentos de C#
Operadores
Instrucciones
Estrcuturas de control.
Definición de clases
Creación de objetos
Herencia y métodos virtuales
Polimorfismo
Ocultación de miembros
Miembros de tipo
Encapsulación
Espacios de nombres
Importación de espacios de nombres
Espacio de nombres distribuidos
Variables y tipos de datos
Tablas unidimensionales
Tablas multidimensionales
La clase System.Array
Cadenas de texto
Constantes
Orden de inicialización de variables
Métodos
Métodos externos
Constructores
Destructores
Propiedades
Indizadores
Redefinición de operadores
Delegados y eventos
La clase MulticastDelegate
Llamadas asíncronas
Implementación interna de los delegados
Eventos
Estructuras
Boxing y unboxing
Constructores de estructuras
Enumeraciones
Interfaces
Excepciones
Otras instrucciones
Atributos
Definición de nuevos atributos
Lectura de atributos en tiempo de ejecución
Atributos de compilación
Pseudoatributos
Código inseguro
Definición de punteros
Manipulación de punteros
Operadores relacionados con código inseguro
Fijación de variables apuntadas
Novedades de C# 2.0
Genéricos
Tipos parciales
Iteradores
Mejoras en la manipulación de delegados
Tipos anulables
Modificadores de visibilidad de bloques get y set
Clases estáticas
Referencias a espacios de nombres
Supresión temporal de avisos
Atributos condicionales
Incrustación de tablas en estructuras
Modificaciones en el compilador
También puedes ver ...
Creando cadenas de conexión ConnectionStrings en .net 3.5 o visual Studio 2008 usando SqlConnectionStringBuilder
Migración de WSE a WCF (Web Services de 2005 a 2008)
Generar archivos PDF con C#
TransactionScope - Simplificando el trabajo con transacciones.
LinQ To SQL - Un ejemplo sencillo
Cómo activar Intelisense (autocompletado) en el Web.config
Leer un campo XML de SQL Server 2005 con C#
TripleDES - Un ejemplo practico en C#
Mostrar un GridView dentro de un DataList
String.Format

Afiliados
La Web del programador
MundoProgramacion


 

Mejoras en la manipulación de delegados

Inferencia de delegados

Mientras que en C# 1.X siempre era necesario indicar explícitamente el delegado del objeto o evento al que añadir cada método utilizando el operador new, como en:

 
miObjeto.miEvento += new MiDelegado(miCódigoRespuesta);

    En C# 2.0 el compilador es capaz de inferirlo automáticamente de la definición del delegado en que se desea almacenar. Así, para el ejemplo anterior bastaría con escribir:


miObjeto.miEvento += miCódigoRespuesta;

    Sin embargo, asignaciones como la siguiente en la que el método no es asociado a un delegado no permiten la deducción automática del mismo y fallarán al compilar:


object o = miCódigoRespuesta;

    Aunque explicitando la conversión a realizar tal y como sigue sí que compilará:


object o = (MiDelegado) miCódigoRespuesta;

    En general, la inferencia de delegados funciona en cualquier contexto en que se espere un objeto delegado. Esto puede observarse en el siguiente ejemplo:


 using System;
 class A
 {
  delegate void MiDelegado(string cadena);
  
  public static void Main()
  {
   // En C# 1.X: MiDelegado delegado = new MiDelegado(miMétodo);
   MiDelegado delegado = miMétodo;
   // En C# 1.X: delegado.EndInvoke(delegado.BeginInvoke("Hola",
   // new AsyncCallback(métodoFin), null));

   delegado.EndInvoke(delegado.BeginInvoke("Hola", métodoFin, null));
  }
     
  static void miMétodo(string cadena)
  {
   Console.WriteLine("MiMétodo(string {0})", cadena);
  }
  static void métodoFin(IAsyncResult datos)
  {
   //…
  }
 }

Métodos anónimos

    C# 2.0 permite asociar código a los objetos delegados directamente, sin que para ello el programador tenga que crear métodos únicamente destinados a acoger su cuerpo y no a, como sería lo apropiado, reutilizar o clarificar funcionalidades. Se les llama métodos anónimos, pues al especificarlos no se les da un nombre sino que se sigue la sintaxis:


delegate(<parámetros>) {<instrucciones>};

    Y será el compilador quien internamente se encargue de declarar métodos con dichos <parámetros> e <instrucciones> y crear un objeto delgado que los referencie. Estas <instrucciones> podrán ser cualesquiera excepto yield, y para evitar colisiones con los nombres de métodos creados por el programador el compilador dará a los métodos en que internamente las encapsulará nombres que contendrán la subcadena reservada __. Nótese que con esta sintaxis no se pueden añadir atributos a los métodos anónimos.

    Con métodos anónimos, las asignaciones de métodos a delegados podría compactarse aún más eliminándoles la declaración explícita del método de respuesta. Por ejemplo:


 miObjeto.miEvento += delegate(object parámetro1, int parámetro2)
    { Console.WriteLine ("Evento producido en miObjeto"); };

    Incluso si, como es el caso, en el código de un método anónimo no se van a utilizar los parámetros del delegado al que se asigna, puede omitirse especificarlos (al llamar a los métodos que almacena a través suya habrá que pasarles valores cualesquiera) Así, la asignación del ejemplo anterior podría compactarse aún más y dejarla en:


miObjeto.miEvento += delegate {
Console.WriteLine ("Evento producido en miObjeto"); };

    En ambos casos, a partir de estas instrucciones el compilador definirá dentro de la clase en que hayan sido incluidas un método privado similar al siguiente:


 public void __AnonymousMethod$00000000(object parámetro1, int parámetro2)
 {
  Console.WriteLine ("Evento producido en miObjeto");
 }

    Y tratará la asignación del método anónimo al evento como si fuese:


miObjeto.miEvento += new MiDelegado(this,__AnonymousMethod$00000000);

    No obstante, la sintaxis abreviada no se puede usar con delegados con parámetros out, puesto que al no poderlos referenciar dentro de su cuerpo será imposible asignarles en el mismo un valor tal y como la semántica de dicho modificador requiere.

    Fíjese que aunque a través de += es posible almacenar métodos anónimos en un objeto delegado,  al no tener nombre no será posible quitárselos con -= a no ser que antes se hayan almacenado en otro objeto delegado, como en por ejemplo:


 MiDelegado delegado = delegate(object párametro1, int parámetro2)
  { Console.WriteLine ("Evento producido en miObjeto"); };
 miObjeto.miEvento += delegado;
 miObjeto.miEvento -= delegado;

    Los métodos anónimos han de definirse en asignaciones a objetos delegados o eventos para que el compilador pueda determinar el delegado donde encapsularlo. Por tanto, no será válido almacenarlos en objects mediante instrucciones del tipo:


 object anónimo = delegate(object párametro1, int parámetro2)
   { Console.WriteLine ("Evento producido en miObjeto"); }; // Error

    Aunque sí si se especificarse el delegado mediante conversiones explícitas, como en:


 object anónimo = (MiDelegado) delegate(object parametro1, int parámetro2)
  { Console.WriteLine ("Evento producido en miObjeto"); };

    Los métodos anónimos también pueden ser pasados como parámetros de los métodos que esperen delegados, como en por ejemplo:


 class A
 {
  delegate void MiDelegado();
  public void MiMétodo()
  {
     LlamarADelegado(delegate() { Console.Write("Hola"); });
  }
  void LlamarADelegado(MiDelegado delegado)
  {
     delegado();
  }                                 
 }

    Nótese que si el método aceptase como parámetros objetos del tipo genérico Delegate, antes de pasarle el método anónimo habría que convertirlo a algún tipo concreto para que el compilador pudiese deducir la signatura del método a generar, y el delegado no podría tomar ningún parámetro ni tener valor de retorno. Es decir:


class A
 {
  public void MiMétodo()
  {
     LlamarADelegado((MiDelegado) delegate { Console.Write("Hola"); });
  }

  void LlamarADelegado(delegate delegado)
  {
     MiDelegado objeto = (MiDelegado) delegado;
     objeto("LlamarADelegado");
  }                                 
 }

Captura de variables externas

    En los métodos anónimos puede accederse a cualquier elemento visible desde el punto de su declaración, tanto a las variables locales de los métodos donde se declaren como a los miembros de sus clases. A dichas variables se les denomina variables externas, y se dice que los métodos anónimos las capturan ya que almacenarán una referencia a su valor que mantendrán entre llamadas. Esto puede observarse en el siguiente ejemplo:


 using System;
 delegate int D(ref VariablesExternas parámetro);
 class VariablesExternas
 {
  public int Valor = 100;
  static D F()
  {
   VariablesExternas o = new VariablesExternas();
   int x = 0;
   D delegado = delegate(ref VariablesExternas parámetro)
      {
       if (parámetro==null)
        parámetro = o;
       else
        parámetro.Valor++;
       return ++x;
      };
   x += 2;
   o.Valor+=2;
   return delegado;
  }
  static void Main()
  {
   D d = F();
   VariablesExternas objeto = null;
   int valor = d(ref objeto);
   Console.WriteLine("valor={0}, objeto.Valor={1}", valor, objeto.Valor);
   valor = d(ref objeto);
   Console.WriteLine("valor={0}, objeto.Valor={1}", valor, objeto.Valor);
  }
 }

     Cuya salida es:

      valor=3, objeto.Valor=102

      valor=4, objeto.Valor=103

    Fíjese que aunque las variables x y o son locales al método F(), se mantienen entra las llamadas que se le realizan a través del objeto delegado d ya que han sido capturadas por el método anónimo que éste almacena.

    A las variables capturadas no se les considera fijas en memoria, por lo que para poderlas manipular con seguridad en código inseguro habrá que encerrarlas en la sentencia fixed.

    Debe señalarse que la captura de variables externas no funciona con los campos de las estructuras, ya que dentro de un método anónimo no se puede referenciar al this de las mismas. Sin embargo, la estructura siempre puede copiarse desde fuera del método anónimo en una variable local para luego referenciarla en el mismo a través de dicha copia. Eso sí, debe señalarse que en un campo de la estructura no se podrá realizar esta copiar ya que ello causaría ciclos en la definición de ésta.

Covarianza y contravarianza de delegados

    Los delegados también son más flexibles en C# 2.0 porque sus objetos admiten tanto métodos que cumplan exactamente con sus definiciones, con valores de retorno y parámetros de exactamente los mismos tipos indicados en éstas, como métodos que los tomen de tipos padres de éstos. A esto se le conoce como covarianza para el caso de los valores de retorno y contravarianza para el de los parámetros. Por ejemplo:


 using System;
 public delegate Persona DelegadoCumpleaños(Persona persona, int nuevaEdad);
 public class Persona
 {
  public string Nombre;
  private int edad;
  
  public int Edad
  {
   get { return this.edad; }
  }
  public event DelegadoCumpleaños Cumpleaños;
  public Persona(String nombre, int edad)
  {
   this.Nombre = nombre;
   this.edad = edad;
  }

  public void CumplirAños()
  {
   Cumpleaños(this, this.edad+1);
   this.edad++;
  }
 }
 public class Empleado:Persona
 {
  public uint Sueldo;
  
  public Empleado(string nombre, int edad, uint sueldo):base(nombre, edad)
  {
   this.Sueldo = sueldo;    
  }
 }
 public class Covarianza
 {
  static void Main()
  {
   Empleado josan = new Empleado("Josan", 25, 500000);
   josan.Cumpleaños += mostrarAños;
   josan.CumplirAños();
  }
  static Persona mostrarAños(Persona josan, int nuevaEdad)
  {
   Console.WriteLine("{0} cumplió {1} años", josan.Nombre, nuevaEdad);
   return josan;
  }
 }

    Nótese que aunque en el ejemplo el delegado se ha definido para operar con objetos del tipo Persona, se le han pasado objetos de su subtipo Empleado y devuelve un objeto también de dicho tipo derivado. Esto es perfectamente seguro ya que en realidad los objetos del tipo Empleado siempre tendrán los miembros que los objetos del Persona y por lo tanto cualquier manipulación que se haga de los mismos en el código será sintácticamente válida. Si lo ejecutamos, la salida que mostrará el código es la siguiente:

 Josan cumplió 26 años

 


Inicio | Tutorial C# IteradoresTutorial C#Tipos anulables Versión para imprimir Foros de consulta


Añadir comentario ... Para preguntar utiliza los foros
Autor:

Título:


Para preguntar utiliza los foros.



Inicio | Tutorial C# IteradoresTutorial C#Tipos anulables Versión para imprimir

Mejoras en la manipulación de delegados
Autor: José Antonio González Seco
Visitas: 3941 Fecha de publicación: 02/01/2007
José Antonio es experto en tecnologias Microsoft. Imparte cursos y conferencias en congresos sobre C# y .NET en Universidades de toda España (Sevilla, Barcelona, San Sebastián, Valencia, Oviedo, etc.) en representación de grandes empresas como Microsoft.




Visitas: 132 | Comentarios: 0 | Archivo: Articulos
Categorias: Visual Basic .NET|C#|ASP.NET|ASP.NET|Programación|ADO.NET
27/09/2008 Navegando ....
Visitas: 56 | Comentarios: 0 | Archivo: Articulos
Categorias: Humor
Visitas: 172 | Comentarios: 0 | Archivo: Articulos
Categorias: Visual Basic .NET|C#|ASP.NET|ASP.NET|Programación|WCF
Visitas: 705 | Comentarios: 0 | Archivo: Articulos
Categorias: C#
Visitas: 176 | Comentarios: 0 | Archivo: Articulos
Categorias: JavaScript|ASP.NET
Visitas: 618 | Comentarios: 0 | Archivo: Articulos
Categorias: Windows XP|Linux|Windows Vista
Visitas: 404 | Comentarios: 0 | Archivo: Articulos
Categorias: Linux|BSD
Visitas: 213 | Comentarios: 0 | Archivo: Articulos
Categorias: Programación|Actualidad
18/08/2008 SQL Server 2008
Visitas: 1029 | Comentarios: 1 | Archivo: Articulos
Categorias: Transact-SQL
Visitas: 728 | Comentarios: 0 | Archivo: Articulos
Categorias: C#|ADO.NET|LinQ

Útimos temas recibidos en los foros ...
Crear una sesion de inicio por jhors ... [ASP.NET] 1 06/10/2008
Enviar email a correos cmo hotmail por Cajami ... [C#] 13 06/09/2007
Como mandar mensaje a Celular por Pako ... [C#] 23 13/03/2007
Casting por sara ... [Java] 1 06/10/2008
ORA-22288: file or LOB operation GetLength failed por heroga ... [ORACLE] 1 05/08/2008
Galeria de imagenes en Visual Web Developer por luis ... [ASP.NET] 0 06/10/2008
utilizar un ObjectDataSource por mari90 ... [ASP.NET] 4 25/10/2006
Llamar procedimientos almacenados por elmago ... [C#] 1 04/10/2008
Procesos huerfanos por cesarf283 ... [SQL Server] 2 11/07/2007
numero autogenerado por lucho ... [Visual Basic .NET] 17 10/01/2007
PUNTO DE VENTA por TIBURON ... [Access] 0 04/10/2008
Curso Visual Basic .NET en vídeo por martaz ... [Visual Basic .NET] 4 08/11/2007

Access CGI JSP ORACLE UNIX
Actualidad HTML/DHTML/XHTML LINUX PHP Visual Basic .NET
ASP ISAPI MS DOS Power Builder Visual Basic 6.0
ASP.NET Java mySQL SQL WIN 98/NT/2000/XP
C# JavaScript Opinion SQL Server

devjoker  Te recomendamos además ...
14/07/2007 Como encriptar texto y variables usando algoritmos estandard como DES o TRIPLEDES
22/10/2005 Vistas    forma parte de...Tutorial SQL
09/10/2006 Variables y tipos de datos    forma parte de...Tutorial C#
21/02/2007 BULK COLLECT    forma parte de...Tutorial PL/SQL
16/08/2007 Operaciones con conjuntos.    forma parte de...Tutorial de Transact SQL
24/05/2006 Cursores Explicitos en PL/SQL    forma parte de...Tutorial PL/SQL
22/10/2005 Consultas combinadas. JOINS    forma parte de...Tutorial SQL
20/03/2008 Funciones integradas de Transact SQL (I)    forma parte de...Tutorial de Transact SQL
09/05/2006 Como leer XML con C#
28/06/2006 Triggers en PL/SQL    forma parte de...Tutorial PL/SQL

 

Encuesta
¿A que perfil te adaptas mejor?
[Ver] [Votar]