El Blog de Óscar Sotorrío Sánchez - MCP Application Development Foundation - C#

Todo lo que vaya aprendiendo de .NET, C#, ASP.NET, SQL Server, etc, lo compartiré con vosotros.

El autor:

Óscar Sotorrío Sánchez
Contacto Send mail

Encuéntralo

Álguien dijo...


¡Tríste época la nuestra!. Es más fácil desíntegrar un átomo que un perjuício.

Albert Einstein

GridView: asignar dinámicamente el texto de CommandField

En ocasiones debemos mostrar informes en controles GridView en los que una, o varias, de sus columnas nos permitan seleccionar una fila para realizar una determinada acción en nuestro código. De forma predeterminada el control GridView nos permite añadir columnas de tipo BoundFile, ButtonField, CheckBoxField, CommandField, HyperLinkField, etc.

El problema con estas columnas es que el texto mostrado por pantalla siempre es el mismo en cada fila del GridView. Por ejemplo, "Seleccionar" para una columna CommnadField de tipo ShowSelectButton.

Pero esto no es lo que queremos conseguir. Se trata de que cada fila en una columna determinada por nosotros muestre el texto de los datos de la fuente de datos.

De esta forma cada registro permite seleccionar esa fila para realizar una acción en función de los datos que contiene. ¡Veamos como!. 

Tenemos el siguiente GridView en nuestro formulario:

         <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" 

            ondatabound="GridView1_DataBound" 
            onselectedindexchanged
="GridView1_SelectedIndexChanged">
            
<Columns>
                
<asp:CommandField ShowSelectButton="true" ButtonType="Link" HeaderText="Proyecto" />
                <
asp:BoundField DataField="Responsable" HeaderText="Responsable" ReadOnly="True" 
                    SortExpression
="Responsable" />
                <
asp:BoundField DataField="Analista" HeaderText="Analista" 
                    SortExpression
="Analista" />
                <
asp:BoundField DataField="FechaInicio" HeaderText="Fecha Inicio" 
                    SortExpression
="FechaInicio" />
                <
asp:BoundField DataField="FechaFin" HeaderText="Fecha Fin" 
                    SortExpression
="FechaFin" />
            </
Columns>
        
</asp:GridView>


Ahora cargamos el GridView con un DataTable por ejemplo en el evento load.

    protected void Page_Load(object sender, EventArgs e)
    {
        
if (!IsPostBack)
        {
            dt 
= new DataTable();
            
dt.Columns.Add("Proyecto");
            
dt.Columns.Add("Responsable");
            
dt.Columns.Add("Analista");
            
dt.Columns.Add("FechaInicio");
            
dt.Columns.Add("FechaFin");

            int 
contador 0;
            foreach 
(DataColumn colum in dt.Columns)
            {
                DataRow dr 
dt.NewRow();
                
dr["Proyecto""000" + contador.ToString();
                
dr["Responsable""Responsable " + contador.ToString();
                
dr["Analista""Analista " + contador.ToString();
                
dr["FechaInicio""Inicio " + contador.ToString();
                
dr["FechaFin""Fin " + contador.ToString();
                
dt.Rows.Add(dr);
                
contador++;
            
}

            GridView1.DataSource 
dt;
            
GridView1.DataBind();
        
}
    }

En el evento OnDataBound asignamos dinámicamente los datos de la columna CommnadField.

    protected void GridView1_DataBound(object sender, EventArgs e)
    {
        
for (int 0i < dt.Rows.Counti++)
        {
            LinkButton lb 
GridView1.Rows[i].Controls[0].Controls[0as LinkButton;
            
lb.Text dt.Rows[i]["Proyecto"].ToString();
        
}
    }

En este caso la fuente de datos era un DataTable que hemos creado a mano pero podíamos haber utilizado cualquier origen de datos. Por ejemplo, si hubiéramos utilizado un objeto SqlDataSource podríamos recuperar los datos de la forma siguiente.

        DataView dv =  SqlDataSource1.Select(new DataSourceSelectArguments()) as DataView;
        
DataTable dt dv.ToTable();

 

Ahora solo nos queda recoger los datos sobre la celda que pulsa el usuario. Utilizaremos para ello el evento OnSelectedIndexChanged.

    protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
    {
        GridView gv 
(GridView)sender;
        int 
filaSeleccionada gv.SelectedIndex;
        
LinkButton lb gv.Rows[filaSeleccionada].Cells[0].Controls[0as LinkButton;
    
}

Posted by Oscar.SS on domingo, 14 de marzo de 2010 14:09
Permalink | Comentarios (0) | Post RSSRSS comment feed

Eventos del ciclo de vida cliente en ASP.NET AJAX

Como ya hemos comentado alguna vez, ASP.NET con AJAX provoca en el servidor los mismo eventos que durante un PostBack en el ciclo de vida de una página. Pero además, cuando tenemos habilitado AJAX en nuestra página, provoca eventos en el ciclo de vida cliente. El conocer estos eventos y su ciclo es muy importante para tener el mayor control y manejo posible de las solicitudes asíncronas.
 
Estos eventos en el cliente son provocados por las clases de la librería de AJAX .NET. Esta librería y las instancias de sus clases están a nuestra disposición automáticamente al incluir un control ScriptManager al inicio de nuestras páginas.
 
Son dos las clases principales que provocan estos eventos durante el ciclo de vida de la página en el cliente. Tenemos la clase Sys.Application que para entendernos es similar a la clase Page del objeto de servidor. Y tenemos la clase Sys.WebForms.PageRequestManager.
 
Veamos por partes como ocurre todo tanto durante un petición síncrona (PostBack), como una petición asíncrona (AJAX).
 
 
Ciclo de eventos cliente durante un PostBack
 
Cuando arrancamos por primera vez nuestra aplicación, o cuando hacemos un viaje al servidor de nuevo, el ciclo de eventos que se provocan en el cliente son los siguientes.
  • Window.load(). Este evento del DOM como ya sabemos se dispara cuando se carga nuestra página.
  • PageRequestManager.pageLoaded(). Este evento se dispara tanto durante una llamada asíncrona como una síncrona cuando se ha actualizado todo el contenido de la página. Es el evento ideal para determinar en el código cliente si la devolución de datos fué realizada por AJAX o por un PostBack.
  • Application.init(). Se dispara cuando se terminan de cargar todos los script de cliente pero antes de que se cree ningún objeto de estos. Es decir, que si intentamos acceder durante este evento a cualquiera de los objetos declarados en nuestros script recibiremos un error. Otra cosa muy importante a tener en cuenta en este evento es que se dispara una única vez por cada devolución de datos síncrona, nunca durante una devolución asíncrona.
  • Application.load(). Este evento se dispara cuando se han cargado todos los objetos de los script de la página.
  • Application.unload(). Entra en acción antes de eliminar todos los objetos script de la página.
  • Window.unload(). Este evento del DOM como se dispara cuando se cierra nuestra ventana del explorador.

 
Ciclo de eventos cliente durante AJAX en .NET
 
Ahora viene lo que realmente debemos tener en cuenta. No olvidemos que estamos trabajando bajo el esquema de un control ScriptManager y un control UpdatePanel en nuestra página. Esto significa que cuando el servidor nos devuelve los datos, se realiza una actualización parcial de la página, en concreto, solo obtenemos el HTML necesario para repintar el contenido de los elementos del interior del UpdatePanel.

  • PageRequestManager.initializeRequest(). Este es el primero de los eventos que se disparan cuando provocamos una llamada AJAX. En realidad, durante este evento aún no ha comenzado la solicitud, por lo tanto, es el evento ideal para cancelar la llamada desde nuestro código cliente.
  • PageRequestManager.beginRequest(). Se provoca antes de que se envíen los datos al servidor. Es el último evento que se produce en el cliente. Es el momento ideal para llamar a un script personal que inicie una animación que notifique al usuario que se está procesando la devolución de datos. El control UpdateProgress hace uso de este evento para mostrar su contenido.
  • PageRequestManager.pageLoading(). Se dispara después de recibir la respuesta del servidor durante una llamada AJAX, pero antes de actualizar cualquier contenido en la página. Es una oportunidad perfecta para realizar cualquier acción personalizada, antes de ser pintados, sobre los datos recibidos desde el servidor, como filtrarlos o formatearlos. También es el evento usado para enviar datos a los controles que no están incluidos en el updatepanel.
  • PageRequestManager.pageLoaded(). Este evento se dispara tanto durante una llamada asíncrona como una síncrona cuando se ha actualizado todo el contenido de la página. Es el evento ideal para determinar en el código cliente si la devolución de datos fué realizada por AJAX o por un PostBack.
  • Application.load(). Este evento se dispara cuando se han cargado todos los objetos de los script de la página.
  • PageRequestManager.endRequest(). Se dispara después del repintado parcial de la página y se devuelve el control al explorador. También se dispara este evento cuando se ha producido un error durante la devolución de datos asíncrona. Si se produce un error, la página no se actualiza por lo tanto los datos devueltos por el servidor no son mostrados. Se puede utilizar este evento para proporcionar una notificación de error personalizada a los usuarios o para registrar los errores. También se utilizar para ejecutar script personalizados al terminar la devolución de datos asíncrona.
 
 
Pues muy bien, mucho rollo pero...¿como se declaran estos eventos en el cliente?. Pongamos todo esto en práctica.
<script type="text/javascript" language="javascript">

        
//Eventos del objeto Application

        
Sys.Application.add_init(applicationInitHandler);

        function 
applicationInitHandler() {
        
//Código para este evento
        
}


        
//Eventos del objeto PageRequestManager

        
Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(prmInitializeRequest);

        function 
prmInitializeRequest() {
        
//Código para este evento
        
}
 </script>
La clase Sys.Application se instacia directamente, no así la clase Sys.WebForms.PageRequestManager que para intstanciarla debemos utilizar el método getInstance().
 
Los eventos de ambas clases se declaran al estilo de los delegados de C#, y siempre siguen la misma sintaxis: add_nombreEvento (nombreFuncion)
 
Podéis descargaros un pequeño ejemplo para jugar con todo esto: EventosClienteAJAX.rar (3,52 kb)
 
 

Posted by Oscar.SS on domingo, 21 de febrero de 2010 19:53
Permalink | Comentarios (2) | Post RSSRSS comment feed

Instalar la libería de AJAX Control Toolkit

La biblioteca de controles AJAX Control Toolkit es una poderosa característica que debemos tener siempre presente. Por ello vamos a ver como se instala en 7 sencillos pasos, para que quede integrada en nuestra herramienta de desarrollo Visual Studio 2008.

1. En primer lugar debemos dirigirnos al sitio oficial de descarga, que no es otro que CodePlex. En el siguiente enlace buscaremos la zona de descarga.

http://ajaxcontroltoolkit.codeplex.com/

 

2. Elegimos la versión que queremos descargar y descomprimimos el zip. En el momento de escribir este artículo esta disponible la versión que se muestra en la imagen.

 

3. Nos dirigimos a nuestro Visual Studio y abrimos un editor de páginas aspx. En el cuadro de herramientas, en la última ficha, "General", con el botón secundario seleccionamos la opción "Agregar Ficha". Le damos un nombre a la nueva ficha, por ejemplo, AJAX Control Toolkit.

 

4. Sobre la superficie de la nueva ficha repetimos la operación y esta vez seleccionamos "Elegir Elementos".

 

5. En la ventana que se abre, elementos del cuadro de herramientas, presionamos el botón "Examinar".

 

6. Buscamos la carpeta que acabamos de descargar y dentro de ella seleccionamos la siguiente dll. 

........./SampleWebSite/Bin/AjaxControlToolkit.dll

 

7. Presionamos el botón "Aceptar" y esperamos a que terminen de cargarse todos los binarios. Y ya tenemos todos los controles de AJAX en el cuadro de herramientas listos para ser utilizados.

¡A disfrutarlo! 


Posted by Oscar.SS on domingo, 07 de febrero de 2010 18:21
Permalink | Comentarios (0) | Post RSSRSS comment feed

IHttpModule: Antes y después de la solicitud

La interfaz IHttpModule nos proporciona una manera simple de manejar las peticiones HTTP antes de que estas comiencen a administrarse en IIS y una vez que han sido totalmente ejecutadas y se van a devolver al cliente.

¿Porque razón querríamos actuar en la solicitud antes (y después) de que comience a administrarse? 

  • Por temas de seguridad y rendimiento. Si un usuario no tiene permisos en nuestra aplicación es mejor denegarle el acceso antes de que su solicitud comience a consumir recursos en el servidor.  Comprobamos que no tiene premisos antes del comienzo de ejecución de ninguno de los eventos del ciclo de vida de la página solicitada (o control de usuario, o servicio Web).
  • Para crear módulos estadísticos sobre las solicitudes de forma global en lugar de hacerlo para las páginas de forma individual.
  • Incluir en la respuesta a la solicitud, encabezados y pies de páginas personalizados para todas las solicitudes.
  • En general, siempre que deseemos actuar antes de que comience a ejecutarse la solicitud en el servidor y justo antes de que se envíe la respuesta al cliente.
 
 
 
La forma de implementar un módulo es muy sencilla. Solo tenemos que crear un archivo de clase, por ejemplo Modulo.cs, y implementar la interfaz IHttpModule. Los miembros de esta interfaz son solo dos. 
  • Init(). Inicializa el módulo y lo prepara para procesar la solicitud HTTP.
  • Disponse(). Elimina los recursos utilizados por el módulo.
Es evidente que la lógica de nuestro módulo deberá implementarse en el método Init(). A continuación podemos ver un sencillo ejemplo que comprueba si el usuario tiene permisos, en caso negativo es transferido a una página en la que se muestra un mensaje.
 
public class ClaseModulo : IHttpModule
{
    
public ClaseModulo(){}

    
public void Dispose() { }

    
public string NombreModulo 
    {
        
get return "MiModulo"}
    }

    
public void Init(HttpApplication aplicacion)
    {
        
/*
         * Definimos los eventos del ciclo de vida de la aplicación sobre los que vamos actuar.
         * En este caso actuamos antes del comienzo de la solicitud y cuando esta termina.
         */
        
aplicacion.BeginRequest += new EventHandler(aplicacion_BeginRequest);
        
aplicacion.EndRequest += new EventHandler(aplicacion_EndRequest);
    
}

    
private void aplicacion_BeginRequest(object sender, EventArgs e)
    {
        
//Obtenemos el contexto de aplicación de la solicitud.
        
HttpApplication Aplicacion (HttpApplication)sender;
        
HttpContext Contexto Aplicacion.Context;

        
//Obtenemos la extensión del archivo solicitado.
        
string Ruta Contexto.Request.FilePath;
        string 
Extension VirtualPathUtility.GetExtension(Ruta);

       
//Si se ha solicitado una página aspx.
        
if (Extension.Equals(".aspx"))
        {
            
//Si el usuario no tiene permisos le enviamos a la página de error.
            
if (!UserTienePermisos())
            {
                Contexto.Server.Transfer(
"Default2.aspx");
            
}
        }
    }

    
private void aplicacion_EndRequest(object sender, EventArgs e)
    {
        
//Obtenemos el contexto de aplicación de la solicitud
        
HttpApplication Aplicacion (HttpApplication)sender;
        
HttpContext Contexto Aplicacion.Context;

        
//Obtenemos el nombre del archivo solicitado.
        
string Ruta Contexto.Request.FilePath;
        string 
Extension VirtualPathUtility.GetExtension(Ruta);

        if 
(Extension.Equals(".aspx"))
        {
            
//Si el usuario no tiene permisos mostramos un mensaje al final de la solicitud.
            
if (!UserTienePermisos())
            {
                Contexto.Response.Write(
"Usted no tiene permisos");
            
}
        }
    }
}
 
Una vez codificada la lógica de nuestro módulo debemos registrarlo en el web.config para ASP.NET tenga en cuenta como tiene que manejar la solicitud.
        <system.web>
            
<httpModules>
                
<add name="MiModulo" type="ClaseModulo"/>
            </
httpModules>
        
</system.web>

Posted by Oscar.SS on sábado, 30 de enero de 2010 14:23
Permalink | Comentarios (0) | Post RSSRSS comment feed

Recopilación y actualización a la versión .NET 4.0

Con motivo del cercano lanzamiento de .NET Framework 4.0, me ha dado por actualizar la información que tenía en este blog de la evolución de .NET desde la versión 1.0. Por ello me he kurrado un gráfico que creo servirá para aclarar el tema del versionado de Microsoft que ciertamente es un jaleo :-(

Y ya de paso he aprovechado para modificar un poco las páginas que podéis encontrar en el menú de la izquierda, donde pone Páginas Extra, referentes a las novedades de C# 2.0C# 3.0C# 4.0. Bueno, en realidad la última versión del lenguaje no la he incluido, aún estoy recopilando la información...sorry!!.

Aquí os dejo el gráfico (click para ampliar).

 

 

Mi idea principal con este gráfico, es dejar más clara la evolución de las tecnologías disponibles en cada versión del framework en cuando a desarrollo con ASP.NET.

Por este motivo podéis encontrar en la fila correspondiente a ASP.NET (color rojo) algunas tecnologías que se han incluido en el framework pero que en realidad no pertenecen al núcleo de ASP.NET. Pero si tienen mucho que ver con el desarrollo web en ASP.NET.

Como referencia, comentar que parte de la información la he extraido del libro de José Manuel Alarcón titulado muy acertadamente "Tecnologías ASP.NET 4.0 (Saltando desde la versión 2.0)".

Por otra parte, animo a todos a comentar cualquier cosilla que se me pase por alto o que sea de interés común incluirlo en el gráfico. 


Posted by Oscar.SS on jueves, 14 de enero de 2010 22:00
Permalink | Comentarios (0) | Post RSSRSS comment feed

GridView: acceder a los valores de las columnas no visibles

Cuando intentamos acceder al valor de una celda, de una columna marcada en el GridView como no visible, nos encotramos ante un problema. Dado que, normalmente las columnas marchadas como no visibles, suelen almacenar datos nada importantes para el usuario (id, codigos, valores ocultos, etc) pero si de suma importancia para el funcionamiento interno de nuestra aplicación.

Por lo tanto, lógicamente el siguiente intento no nos devolverá nada porque la columna no visible no ha sido "pintada".

string id gvEmpleados.Rows[e.RowIndex].Cells[celdaId].Text;

Para resolver este pequeño problema debemos utilizar las propiedades DataKayNames y Datakeys del GridView. Veamos un ejemplo.

Tenemos el siguiente XML que deseamos mostrar por pantalla al usuario por medio de una rejilla como GridView.

<?xml version="1.0" encoding="utf-8"?>
<empleados>
    
<empleado id="1" idEmpresa="034/9435" Nombre="Pedro" Telefono="985945452" Pais="Mexico" />
    <
empleado id="2" idEmpresa="035/3245" Nombre="Antonio" Telefono="887404730" Pais="Perú" />
    <
empleado id="3" idEmpresa="078/4324" Nombre="Jorge" Telefono="9149858353" Pais="España" />
    <
empleado id="4" idEmpresa="045/3243" Nombre="Elena" Telefono="893737581" Pais="Argentina" />
    <
empleado id="5" idEmpresa="074/5425" Nombre="Raquel" Telefono="9984573423" Pais="España" />
</
empleados> 

Nuestro GridView tendrá la siguiente definición de código HTML en nuestra página.

 

<asp:GridView ID="gvEmpleados" runat="server" AutoGenerateColumns="False" 
            DataSourceID
="XmlDataSourceEmpleados" DataKeyNames="id,idEmpresa" 
            onrowdeleting
="gvEmpleados_RowDeleting" 
            onselectedindexchanging
="gvEmpleados_SelectedIndexChanging">
            
<Columns>
                
<asp:CommandField ShowSelectButton="True" />
                <
asp:BoundField DataField="id" HeaderText="id" SortExpression="id" 
                    Visible
="False" />
                <
asp:BoundField DataField="idEmpresa" HeaderText="idEmpresa" 
                    SortExpression
="idEmpresa" Visible="False" />
                <
asp:BoundField DataField="Nombre" HeaderText="Nombre" 
                    SortExpression
="Nombre" />
                <
asp:BoundField DataField="Telefono" HeaderText="Telefono" 
                    SortExpression
="Telefono" />
                <
asp:BoundField DataField="Pais" HeaderText="Pais" SortExpression="Pais" />
                <
asp:CommandField ShowDeleteButton="True" />
            </
Columns>
        
</asp:GridView>
        
<asp:XmlDataSource ID="XmlDataSourceEmpleados" runat="server" 
            DataFile
="~/App_Data/empleados.xml"></asp:XmlDataSource>
He marcado en negrita y un poco más grande las columnas no visibles al usuario. También podemos ver la propiedad DataKeyNames. Esta propiedad permite establecer (también recuperar) una colección de columnas que serán tratadas como claves primarias del origen de datos.
 
Ahora solo nos queda desde código acceder a estos valores cuando el usuario dispare cualquiera de los eventos del GridView. Ya sea para actualizar, eliminar, seleccionar, etc una fila. Un par de ejemplos:
 
 
    protected void gvEmpleados_SelectedIndexChanging(object sender, GridViewSelectEventArgs e)
    {
        var colsNoVisible 
gvEmpleados.DataKeys[e.NewSelectedIndex].Values;
        string 
id (string)colsNoVisible[0];
        string 
idEmpresa (string)colsNoVisible[1];
    
}
    
protected void gvEmpleados_RowDeleting(object sender, GridViewDeleteEventArgs e)
    {
        var colsNoVisible 
gvEmpleados.DataKeys[e.RowIndex].Values;
        string 
id (string) colsNoVisible[0];
        string 
idEmpresa (string) colsNoVisible[1];
    
}

La propiedad DataKeys nos permite acceder a las columnas que son tratadas como claves primarias en el origen de datos. De esta forma nosotros podemos trabajar por debajo con registros únicos como ids y mostrar al usuario solo la información que le interesa.

 


Posted by Oscar.SS on domingo, 06 de diciembre de 2009 15:26
Permalink | Comentarios (0) | Post RSSRSS comment feed

DataGridView: posicionar scroll

Esta es una cuestión muy simple y sencilla pero me ha parecido correcto incluirla en un post porque es de ese tipo de cosas que siempre se preguntan y nadie escribe sobre ello porque parece demasiado trivial.

Supongamos el caso de un DataGridView que contiene multitud de líneas y el usuario se desplaza por el mismo con un scroll vertical. En un momento dado el usuario cambia el contenido de una celda y actualiza para que los cambios sean volcados en la base de datos que alimenta el DataGridView.

¿Qué ocurre?. Que al actualizar el scroll sube a la parte de arriba, perdiendo de vista en la pantalla el cambio efectuado.

La solución es la siguiente:

            int indiceFilaSelec dataGridView1.CurrentRow.Index;
            
dataGridView1.FirstDisplayedScrollingRowIndex indiceFilaSelec;

También se puede obtener el índice de la fila seleccionada con dataGridView1.SelectedRows[0].Index;


Posted by Oscar.SS on jueves, 02 de julio de 2009 8:51
Permalink | Comentarios (0) | Post RSSRSS comment feed

Programación Orientada a Objetos en .NET con C# (5ª parte)

2. Encapsulación

d-Miembros de una clase (constructores (1))

 

Los constructores son el punto de inicio de una clase. Esto quiere decir, que cuando creamos un objeto a partir de una clase, el primer código que se ejecuta es el código contenido en el cuerpo del constructor. Por esta razón, los constructores normalmente se utilizan para inicializar los campos o variables de la clase.

Una clase obligadamente siempre tiene que tener un constructor. En le caso de que no implementemos ninguno, será el propio compilador de C#, el que asigne forzosamente uno a nuestra clase y será utilizado por el compilador para realizar operaciones internas de cara a la construción de objetos. A este constructor, se le conoce con el nombre de constructor predeterminado.

Ahora vamos a implementar un constuctor a nuestra clase  'Empleado' que utilizamos en el artículo anterior. ¡Veamos como!.

   class Empleado
   {
      
public string Nombre;

      public 
Empleado()
      {
         Nombre 
"Pablo";
      
}
   }

Para intentar hacerlo más didáctico he añadido a la clase un campo 'Nombre'. Este campo es inicializado desde el constructor como comentamos anteriormente. Ahora, cuando creamos un objeto a partir de esta clase, el constructor asignará en primer lugar 'Pablo' a la variable 'Nombre'. 

 

Como se puede apreciar, el constructor esta compuesto de 4 partes:

1- Modificador de accesibilidad: Pueden ser declarados como public, protected. internal, protected internal y private.

2- Identificador del constuctor: Siempre coincide con el nombre de la clase, en este caso 'Empleado'

3- Paréntesis de parámetros: Dentro de los paréntesis podemos asignar todos lo parámetros que necesitemos. Luego veremos un ejemplo.

4- Cuerpo del constructor: Aquí se ejecuta el código del constructor.

 

Sobrecarga de constructores. 

Una clase puede tener más de un constructor. En realidad, tantos como necesitemos.

Para implementar más de un constructor en una misma clase, es necesario que los constructores se diferencien o bien en el tipo de parámetros o en el número de ellos. Continuando con el ejemplo anterior:

   class Empleado
   {
      
public string Nombre;

      public 
Empleado()
      {
         Nombre 
"Pablo";
      
}

      
public Empleado(string Nom)
      {
         Nombre 
Nom;
      
}
   }

Ahora tenemos dos constructores en la clase 'Empleado'. Uno sin parámetros y otro con un parámetro de tipo System.String. Ambos constructores se utilizan para inicializar el campo Nombre.

Cada constructor implementado en una clase nos indica como podemos o debemos utilizar la clase para construir los objetos a partir de ella.

 

Construir objetos.

Para construir un objeto en nuestro código a partir de una clase utilizaremos el operador new de la siguiente forma.

 

      NombreClase  NombreObjeto  =  new  Constructor; 

 

        Empleado Empleado1 = new Empleado();

 

El operador new reserva espacio en la memoria para el objeto creado. En algunas fuentes llaman a esto instanciar un objeto. No debemos asustarnos por esta "palabreja". Instanciar un objeto es cargarlo en la memoria y para ello utilizamos el operador new.

Posiblemente, todo esto sea más facil de enterder si lo vemos paso a paso.

Primero creamos un objeto de tipo 'Empleado'.

 

        Empleado Empleado1;

 

Y una vez que tenemos el objeto creado, podemos cargarlo en la memoria por medio del operador new.

 

        Empleado1 = new Empleado();

 

En este caso, hemos utilizado de la clase 'Empleado' el constructor sin parámetros. Por lo tanto el objeto 'Empleado1' tendrá el campo 'Nombre' con el valor de Pablo. De hecho, cualquier objeto creado a partir de la clase con este constructor tendrá el mismo valor para 'Nombre'.

Pero también podiamos haber procedido así:

 

        Empleado Empleado2 = new Empleado("Jorge");

 

De esta forma, el objeto 'Empleado2' tendrá Jorge como valor del campo 'Nombre'.

 

Es lógico pensar que los constructores nos indican como podemos crear los objetos a partir de la clase. Utilizando un constructor u otro, los objetos se irán cargando en la memoria con unos valores u otros.


Posted by Oscar.SS on domingo, 15 de febrero de 2009 0:08
Permalink | Comentarios (0) | Post RSSRSS comment feed

Programación Orientada a Objetos en .NET con C# (4ª parte)

2. Encapsulación

c- Clases en C# (declaración y accesibilidad)

 

En el artículo anterior vimos como la encapsulación estaba directamente relacionada con las clases y la relación de estas con los objetos. Ahora vamos a ver cómo hacer uso de las clases desde nuestro código C#.

Definir una clase en C# es muy sencillo. Solo tenemos que utilizar la palabra reservada "class" seguida del nombre que queramos darle a nuestra clase.

    class Empleados
    {
 
    }

De esta forma ya tenemos una clase (también llamado tipo definido por el usuario) con la que podemos empezar a trabajar. Antes de continuar hablando de los miembros que podemos implementar en una clase debemos hacer una pausa para hablar de los modificadores de accesibilidad.

 

Modificadores de accesibilidad en .NET

Los modificadores de accesibilidad permiten definir el nivel de acceso que tendrán los tipos y los miembros de estos tipos para otros usuarios. Entendiendo por otros usuarios a otros tipos que pertenezcan al mismo proyecto o incluso a un proyecto distinto. Veamos estos modificadores por orden de accesibilidad de mayor a menor.

- public: Un tipo o miembro declarado public puede ser usado desde cualquier código que pertenezca al mismo proyecto o a un proyecto diferente. Es el modificador menos restrictivo de todos.

- internal: Un tipo o miembro declarado internal puede ser usado desde cualquier código que pertenezca al mismo proyecto. Debemos verlo como un tipo o miembro interno de nuestro proyecto.

- protected: Un tipo o miembro declarado protected solo puede ser usado por el código de la misma clase o por código de una clase derivada.

- protected internal: Es una mezcla de los dos anteriores. Puede ser usado por código que pertenezca al mismo proyecto y por código de la misma clase o de una clase derivada.

- private: Un tipo o miembro declarado private solo puede ser usado por código de la misma clase o estructura. Es el más restrictivo de todos los modificadores de accesibilidad.

Todos los tipos (y los miembros de los tipos) tienen un determinado tipo de accesibilidad predefinido. Es decir, si no utilizamos ninguno de los anteriores, el compilador de C# asignará uno por defecto. Normalmente en este estudio hablaremos de las clases por ser el tipo definido por el usuario más flexible y potente, pero en la siguiente tabla podemos ver que modificadores de accesibilidad por defecto corresponden a cada tipo.

 

 

TIPOS

Declarado en ámbito de namespace

Accesibilidad predeterminada

Accesibilidad declarada permitida

Enum

Public

Internal

Public

Class

Internal

 

Internal

Public

Interface

Public

Internal

Public

Struct

Internal

Internal

                 Public               

 

 Nota: Los miembros de las clases tales como métodos y propiedades pueden ser declarados utilizando cualquiera de los modificadores de accesibilidad, teniendo como accesibilidad predeterminada private.

Según todo lo explicado, es fácil deducir que en la declaración de nuestra clase  Empleado, como no especificamos un modificador de accesibilidad, tendrá la accesibilidad Internal.

Bueno, ahora que tenemos claro (eso espero) todo este lío de los modificadores de accesibilidad, vamos a ver en profundidad los miembros que normalmente implementaremos en una clase.

La forma de implementar una clase dependerá en gran medida de las exigencias de nuestro código y de la finalidad de la clase misma. Pero normalmente una clase será un contenedor para los siguientes miembros:

- Constructores.

- Atributos.

- Propiedades.

- Campos.

- Métodos.

- Otros tipos.

- Destructor.

 

 En los artículos siguientes trataremos cada uno de estos miembros en profundidad. La comprensión de los conceptos relacionados con la implementación de los miembros de una clase es de suma importacia para enfocar los restantes pilares (herencia y polimorfismo) de la programación orientada a objetos.

 


Posted by Oscar.SS on lunes, 08 de diciembre de 2008 2:50
Permalink | Comentarios (0) | Post RSSRSS comment feed

Los String...¡unos tipos de cuidado!.

El tipo System.String, que como todos sabemos representa una cadena, es un tipo algo especial con el que hay que tener un poco de cuidado a la hora de menejarlo. Veamos en primer lugar una definición más o menos formal del tipo System.String:

"El tipo System.String es un tipo por referencia e inmutable (de solo lectura) que representa una cadena de texto como una colección secuencial de caracteres Unicode (objetos System.Char)".

 Para este artículo nos centraremos en la primera parte de la definición, es decir, en "El tipo System.String es un tipo por referencia e inmutable (de solo lectura) ...".

¿Que quiere decir que es inmutable?

Un objeto inmutable es un objeto que no se puede modificar. Cuando creas, o cargas en menoria un objeto de este tipo, permanece con el mismo valor durente toda la vida del objeto. Veamos el siguiente fragmento de código:

            string miCadena "Un saludo";
            
miCadena +" para el lector";

Quizás pueda parecer que en la segunda linea de este fragmento estamos modificando el literal "Un saludo" pero esto no es así. Como ya dijimos antes, el objeto "Un saludo" es inmutable, por lo tanto, despúes de la concatenación, lo que se devuelve es un nuevo objeto de tipo System.String que contiene la modificación: "Un saludo para el lector".

Por lo tanto, cuando concatenamos cadenas de esta forma, tenemos en la memoria dos objetos, uno con el valor original y otro con la modificación. Es evidente, que sí esta operación la realizamos miles de veces, por ejemplo leyendo de una base de datos, el rendimiento de la aplicación se verá gravemente afectado. Por otro lado, si la operación solo se realiza una o dos veces (incluso tres o cuatro) no tiene tanta importancia.

Supongamos que tenemos una base de datos con todos los nombre de los lectores de este blog, y supongamos que son miles los nombres guardados (¡ojalá!...jeje). Ahora queremos leer de la base de datos todos los nombres y saludarles por pantalla. Creamos un método al que le pasamos cada nombre leido en un bucle.

        static void Saludar(string Nombre)
        {
            StringBuilder sb 
= new StringBuilder("Hola para ");
            
sb.Append(Nombre);
            
Console.WriteLine(sb.ToString());
        
}

Esta es la manera correcta de proceder, creando un objeto System.Text.StringBuilder y añadiendo cada nueva cadena por medio de su método Append(). Si queréis podéis descargaros un pequeño programilla que calcula el tiempo que se tarda en realizar concatenaciones con System.String y System.Text.StringBuilder en función de un número de iteraciones introducidas por el usuario.

String_vs_StringBuilder.rar (21,95 kb)

 

Más cosas a tener en cuenta.

¿Más cosas a tener en cuenta?. Ya dijimos que eran...¡unos tipos de cuidado!.

Cuando inicializamos variables de tipo Sytem.String y queremos darles un valor por defecto de cadena vacia es muy frecuente hacerlo con las comillas "".

    class Lector
    {
        
public string Nombre;
        public string 
Apellidos;
        public string 
Direccion;
        public string 
Telefono;
        public string 
Comentario;
        public string 
FechaComentario;

        public 
Lector()
        {
            Nombre 
"";
            
Apellidos "";
            
Direccion "";
            
Telefono "";
            
Comentario "";
            
FechaComentario "";
        
}

        
//...............

        //Aquí el resto de mienbros de la clase.

        //...............
    
}

No es recomendable hacerlo de esta forma. En este caso hemos creado (cargado en la menoria) 6 objetos diferentes de tipo cadena. Y seguramente luego "intentaremos" modificarlos al asignarles un valor determinado. Lo correcto, o por lo menos más recomendable, es hacerlo así:

 

        public Lector()
        {
            Nombre 
String.Empty;
            
Apellidos String.Empty;
            
Direccion String.Empty;
            
Telefono String.Empty;
            
Comentario String.Empty;
            
FechaComentario String.Empty;
        
}

Al utilizar el campo String.Empty que representa una cadena vacía, estamos apuntando todas las variables a un mismo objeto. De esta forma solo reservamos memoria para un único objeto gracias a que los tipos System.String son tipos por refencia.

Bueno...ya sabéis...¡cuidado con estos "tipos"!.


Tags:
Categories: Desarrollo .NET
Posted by Oscar.SS on domingo, 30 de noviembre de 2008 3:11
Permalink | Comentarios (0) | Post RSSRSS comment feed