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 ...
SubVersion y Visual Studio
Encriptación con AES Rijndael - Ejemplo
TripleDES - Un ejemplo practico en C#
Insertar una marca de agua en documentos PDF
Serialización: XmlSerializer y BinaryFormater
Handler para manipular imagenes
Conversiones de tipos personalizadas (VB y C#)
Compresión por gzip y deflate
La página Web que está abriendo contiene tanto elementos seguros como no seguros.
Cómo insertar un fichero .xml en un campo de tipo XML de SQL server 2005 o 2008


Constructores

Concepto de constructores

    Los constructores de un tipo de datos son métodos especiales que se definen como miembros de éste y que contienen código a ejecutar cada vez que se cree un objeto de ese tipo. Éste código suele usarse para labores de inicialización de los campos del objeto a crear, sobre todo cuando el valor de éstos no es constante o incluye acciones más allá de una asignación de valor (aperturas de ficheros, accesos a redes, etc.)

    Hay que tener en cuenta que la ejecución del constructor siempre se realiza después de haberse inicializado todos los campos del objeto, ya sea con los valores iniciales que se hubiesen especificado en su definición o dejándolos con el valor por defecto de su tipo.

    Aparte de su especial sintaxis de definición, los constructores y los métodos normales tienen una diferencia muy importante: los constructores no se heredan.

Definición de constructores

    La sintaxis básica de definición de constructores consiste en definirlos como cualquier otro método pero dándoles el mismo nombre que el tipo de dato al que pertenecen y no indicando el tipo de valor de retorno debido a que nunca pueden devolver nada. Es decir, se usa la sintaxis:


<modificadores> <nombreTipo>(<parámetros>)
{
 <código>
}

    Un constructor nunca puede devolver ningún tipo de objeto porque, como ya se ha visto, sólo se usa junto al operador new, que devuelve una referencia al objeto recién creado. Por ello, es absurdo que devuelva algún valor ya que nunca podría ser capturado en tanto que new nunca lo devolvería. Por esta razón el compilador considera erróneo indicar algún tipo de retorno en su definición, incluso aunque se indique void.

Llamada al constructor

    Al constructor de una clase se le llama en el momento en que se crea algún objeto de la misma usando el operador new. De hecho, la forma de uso de este operador es:


new <llamadaConstructor>

    Por ejemplo, el siguiente programa demuestra cómo al crearse un objeto se ejecutan las instrucciones de su constructor:


class Prueba
{
 Prueba(int x)
 {
  System.Console.Write("Creado objeto Prueba con x={0}",x);
 }
 public static void Main()
 {
  Prueba p = new Prueba(5);
 }
}

    La salida por pantalla de este programa demuestra que se ha llamado al constructor del objeto de clase Prueba creado en Main(), pues es:



Creado objeto Prueba con x=5;

 

Llamadas entre constructores

     Al igual que ocurre con cualquier otro método, también es posible sobrecargar los constructores. Es decir, se pueden definir varios constructores siempre y cuando éstos tomen diferentes números o tipos de parámetros. Además, desde el código de un constructor puede llamarse a otros constructores del mismo tipo de dato antes de ejecutar las instrucciones del cuerpo del primero. Para ello se añade un inicializador this al constructor, que es estructura que precede a la llave de apertura de su cuerpo tal y como se muestra en el siguiente ejemplo:


class A
{
 int total;
 
 A(int valor): this(valor, 2);  // (1)
 {
 }
 
 A(int valor, int peso) // (2)
 {
  total = valor*peso;
 }
}

     El this incluido hace que la llamada al constructor (1) de la clase A provoque una llamada al constructor (2) de esa misma clase en la que se le pase como primer parámetro el valor originalmente pasado al constructor (1) y como segundo parámetro el valor 2. Es importante señalar que la llamada al constructor (2) en (1) se hace antes de ejecutar cualquier instrucción de (1)

     Nótese que la sobrecarga de constructores -y de cualquier método en general- es un buen modo de definir versiones más compactas de métodos de uso frecuente en las que se tomen valores por defecto para parámetros de otras versiones menos compactas del mismo método. La implementación de estas versiones compactas consistiría en hacer una llamada a la versión menos compacta del método en la que se le pasen esos valores por defecto (a través del this en el caso de los constructores) y si acaso luego (y/o antes, si no es un constructor) se hagan labores específicas en el cuerpo del método compacto.

     Del mismo modo que en la definición de un constructor de un tipo de datos es posible llamar a otros constructores del mismo tipo de datos, también es posible hacer llamadas a constructores de su tipo padre sustituyendo en su inicializador la palabra reservada this por base. Por ejemplo:


class A
{
 int total;
 
 A(int valor, int peso)
 {
  total = valor*peso;
 }
}
class B:A
{
 B(int valor):base(valor,2)
 {}
}

    En ambos casos, los valores pasados como parámetros en el inicializador no pueden contener referencias a campos del objeto que se esté creando, ya que se considera que un objeto no está creado hasta que no se ejecute su constructor y, por tanto, al llamar al inicializador aún no está creado. Sin embargo, lo que sí pueden incluir son referencias a los parámetros con los que se llamó al constructor. Por ejemplo, sería válido hacer:


A(int x, int y): this(x+y)
{}

Constructor por defecto

    Todo tipo de datos ha de disponer de al menos un constructor. Cuando se define un tipo sin especificar ninguno el compilador considera que implícitamente se ha definido uno  sin cuerpo ni parámetros de la siguiente forma:


public <nombreClase>(): base()
{}

    En el caso de que el tipo sea una clase abstracta, entonces el constructor por defecto introducido es el que se muestra a continuación, ya que el anterior no sería válido porque permitiría crear objetos de la clase a la que pertenece:


protected <nombreClase>(): base()
{}

    En el momento en se defina explícitamente algún constructor el compilador dejará de introducir implícitamente el anterior. Hay que tener especial cuidado con la llamada que este constructor por defecto realiza en su inicializador, pues pueden producirse errores como el del siguiente ejemplo:


class A
{
 public A(int x)
 {}
}
class B:A
{
 public static void Main()
 {
  B b = new B();  // Error: No hay constructor base
 }
}

    En este caso, la creación del objeto de clase B en Main() no es posible debido a que el constructor que por defecto el compilador crea para la clase B llama al constructor sin parámetros de su clase base A, pero A carece de dicho constructor porque no se le ha definido explícitamente ninguno con esas características pero se le ha definido otro que ha hecho que el compilador no le defina implícitamente el primero.

    Otro error que podría darse consistiría en que aunque el tipo padre tuviese un constructor sin parámetros, éste fuese privado y por tanto inaccesible para el tipo hijo.

    También es importante señalar que aún en el caso de que definamos nuestras propios constructores, si no especificamos un inicializador el compilador introducirá por nosotros uno de la forma :base() Por tanto, en estos casos también hay que asegurarse de que el tipo donde se haya definido el constructor herede de otro que tenga un constructor sin parámetros no privado.

Llamadas polimórficas en constructores

    Es conveniente evitar en la medida de lo posible la realización de llamadas a métodos virtuales dentro de los constructores, ya que ello puede provocar errores muy difíciles de detectar debido a que se ejecuten métodos cuando la parte del objeto que manipulan aún no se ha sido inicializado. Un ejemplo de esto es el siguiente:


using System;
public class Base
{
 public Base()
 {
  Console.WriteLine("Constructor de Base");
  this.F();
 }
 
 public virtual void F()
 {
  Console.WriteLine("Base.F");               
 }
}
public class Derivada:Base
{
 Derivada()
 {
  Console.WriteLine("Constructor de Derivada");
 }
 
 public override void F()
 {
  Console.WriteLine("Derivada.F()");
 }
 
 public static void Main()
 {
  Base b = new Derivada();                      
 }
}

    La salida por pantalla mostrada por este programa al ejecutarse es la siguiente:

Constructor de Base

Derivada.F()

Constructor de Derivada

    Lo que ha ocurrido es lo siguiente: Al crearse el objeto Derivada se ha llamado a su constructor sin parámetros, que como no tiene inicializador implícitamente llama al constructor sin parámetros de su clase base. El constructor de Base realiza una llamada al método virtual F(), y como el verdadero tipo del objeto que se está construyendo es Derivada, entonces la versión del método virtual ejecutada es la redefinición del mismo incluida en dicha clase. Por último, se termina llamando al constructor de Derivada y finaliza la construcción del objeto.

    Nótese que se ha ejecutado el método F() de Derivada antes que el código del constructor de dicha clase, por lo que si ese método manipulase campos definidos en Derivada que se inicializasen a través de constructor, se habría accedido a ellos antes de inicializarlos y ello seguramente provocaría errores de causas difíciles de averiguar.

Constructor de tipo

    Todo tipo puede tener opcionalmente un constructor de tipo, que es un método especial que funciona de forma similar a los constructores ordinarios sólo que para lo que se usa es para inicializar los campos static del tipo donde se ha definido.

    Cada tipo de dato sólo puede tener un constructor de tipo. Éste constructor es llamado automáticamente por el compilador la primera vez que se accede al tipo, ya sea para crear objetos del mismo o para acceder a sus campos estáticos. Esta llamada se hace justo después de inicializar los campos estáticos del tipo con los valores iniciales especificados al definirlos (o, en su ausencia, con los valores por defecto de sus tipos de dato), por lo que el programador no tiene forma de controlar la forma en que se le llama y, por tanto, no puede pasarle parámetros que condicionen su ejecución.

    Como cada tipo sólo puede tener un constructor de tipo no tiene sentido poder usar this en su inicializador para llamar a otro. Y además, tampoco tiene sentido usar base debido a que éste siempre hará referencia al constructor de tipo sin parámetros de su  clase base. O sea, un constructor de tipo no puede tener inicializador.

    Además, no tiene sentido darle modificadores de acceso ya que el programador nunca lo podrá llamar sino que sólo será llamado automáticamente y sólo al accederse al tipo por primera vez. Como es absurdo, el compilador considera un error dárselos.

    La forma en que se define el constructor de tipo es similar a la de los constructores normales, sólo que ahora la definición ha de ir prefijada del modificador static y no puede contar con parámetros ni inicializador. O sea, se define de la siguiente manera:


static <nombreTipo>()
{
 <código>
}

   
En la especificación de C# no se ha recogido cuál ha de ser el orden exacto de las llamadas a los constructores de tipos cuando se combinan con herencia, aunque lo que sí se indica es que se ha de asegurar de que no se accede a un campo estático sin haberse ejecutado antes su constructor de tipo. Todo esto puede verse más claro con un ejemplo:


using System;
class A
{
 public static X;
 static A()
 {
  Console.WriteLine("Constructor de A");
  X=1;
 }
}
class B:A
{
 static B()
 {
  Console.WriteLine("Constructor de B");
  X=2;
 }
 
 public static void Main()
 {
  B b = new B();
  Console.WriteLine(B.X);
 }
}

    La salida que muestra por pantalla la ejecución de este programa es la siguiente:


Inicializada clase B

Inicializada clase A

2

    En principio la salida de este programa puede resultar confusa debido a que los primeros dos mensajes parecen dar la sensación de que la creación del objeto b provocó que se ejecutase el constructor de la clase hija antes que al de la clase padre, pero el último mensaje se corresponde con una ejecución en el orden opuesto. Pues bien, lo que ha ocurrido es lo siguiente: como el orden de llamada a constructores de tipo no está establecido, el compilador de Microsoft ha llamado antes al de la clase hija y por ello el primer mensaje mostrado es Inicializada clase B. Sin embargo, cuando en este constructor se va a acceder al campo X se detecta que la clase donde se definió aún no está inicializada y entonces se llama a su constructor de tipo, lo que hace que se muestre el mensaje Incializada clase A. Tras esta llamada se machaca el valor que el constructor de A dió a X (valor 1) por el valor que el constructor de B le da (valor 2) Finalmente, el último WriteLine() muestra un 2, que es el último valor escrito en X.


Inicio | Tutorial C# Métodos externosTutorial C#Destructores Versión para imprimir Foros de consulta

 
mostrar los tipos por valor, r... por Anónimo
Respuesta recibida el [19/02/2008 06:29:32]
mostrar los tipos por valor, referencia en c#

 
Gracias por aristides_03
Respuesta recibida el [21/11/2008 04:52:41]
gracias por el tutorial muy entendible  

 
Excelente por Acosta Sebastian
Respuesta recibida el [15/05/2009 11:59:25]
He leisod un par de libros y el MSDN de Csharp y ningunno fue tan claro como este Articulo , mis felicitaciones y admiracion

 
mas muestra y ejemplo para entnder por josy
Respuesta recibida el [06/10/2009 04:53:30]
¿ejemplo para entender y mas explicaciones y ejercicios okey bye cuidense '

 
muchas gracias explicas mu... por jhon
Respuesta recibida el [07/01/2010 04:38:08]
 muchas gracias    explicas muy bien  se te entiende a la perfeccion felicitaciones


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

Título:


Para preguntar utiliza los foros.



Inicio | Tutorial C# Métodos externosTutorial C#Destructores Versión para imprimir

Constructores
Autor: José Antonio González Seco
Visitas: 18698 Fecha de publicación: 13/10/2006
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: 81 | Comentarios: 2 | Archivo: Articulos
02/02/2010 iPad vs Telesketch
Visitas: 786 | Comentarios: 2 | Archivo: Articulos
Categorias: Humor
Visitas: 725 | Comentarios: 3 | Archivo: Articulos
Visitas: 3116 | Comentarios: 2 | Archivo: Articulos
Categorias: C#
Visitas: 14470 | Comentarios: 7 | Archivo: Articulos
Categorias: C#|Seguridad
Visitas: 1462 | Comentarios: 3 | Archivo: Articulos
Visitas: 688 | Comentarios: 2 | Archivo: Articulos
Visitas: 367 | Comentarios: 0 | Archivo: Articulos
Visitas: 1983 | Comentarios: 2 | Archivo: Articulos
Categorias: C#

Útimos temas recibidos en los foros ...
certificado de afiliación de pensiones y cesantias por secre ... [Actualidad] 107 28/01/2010
Certificadoo por Francy ... [Actualidad] 0 10/03/2010
FORMULARIO ACCESS por jcifuentes ... [Access] 34 29/05/2007
certificado de pensiones del bbva horizonte por danger ... [Actualidad] 119 12/01/2010
Certificado por Francy ... [Actualidad] 0 10/03/2010
certificado de pensión y ses antias por hernan ... [Actualidad] 0 10/03/2010
Certificado de Penciones Horizonte por orlandossa ... [Actualidad] 4 09/02/2010
fondo de pensiones por mafe ... [Access] 0 10/03/2010
certificado del fondo de pensiones cc 10.491.465 santander de Q. por carlos andres cifuentes banguero ... [Actualidad] 9 17/02/2010
certificado de semanas cotisadaz por lis ... [Actualidad] 0 10/03/2010
certificado por arme ... [Actualidad] 0 10/03/2010
Quiero saber a que fondo de pensiones estoy afiliada por clau ... [Actualidad] 169 24/07/2009

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 ...
13/04/2008 String.Format
23/05/2006 Cursores en PL/SQL    forma parte de...Tutorial PL/SQL
09/10/2006 Variables y tipos de datos    forma parte de...Tutorial C#
22/10/2005 Componentes del lenguaje SQL    forma parte de...Tutorial SQL
13/01/2007 Atributos condicionales    forma parte de...Tutorial C#
01/01/2006 Consultas agregadas    forma parte de...Tutorial SQL
19/10/2006 Llamadas asíncronas    forma parte de...Tutorial C#
22/10/2005 Introducción SQL    forma parte de...Tutorial SQL
10/06/2007 Multiples escritorios en Windows XP
02/09/2007 Procedimientos almacenados en Transact SQL    forma parte de...Tutorial de Transact SQL

 

Encuesta
¿A que perfil te adaptas mejor?




[Ver] [Votar]