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...


Encuentro la televisión muy educativa. Cada vez que alguien la enciende, me retiro a otra habitación y leo un libro.

Groucho Marx

Métodos parciales

Si ya conoces la funcionalidad de las clases parciales introducidas en C# 2.0 rapidamente prodrás intuir que son los métodos parciales introducidos como novedad en C# 3.0. Y como ya habrás deducido, los métodos parciales trabajan en el contexto de clases parciales.

En primer lugar veremos como utilizarlos con ejemplos de código, luego hablaremos brevemente cuando utilizarlos y finalmente daremos algunas consideraciones a tener en cuenta.

Vamos a definir una clase parcial que estará implementada en dos ficheros de código diferentes. Por ejemplo, este sería el primer archivo de código:

 

public partial class SaludoPersona
{  
	//Definición del método parcial. Solo contiene la firma del método, no contiene código.  
	partial void SaludarConNombre(string nombre);
  
	public void Saludar()  
 	{    
		Console.WriteLine("Hola ");    
		SaludarConNombre("Oscar");  
	}
}

 

Y a continuación el resto del código de la clase parcial que como hemos mencionado antes, normalmente estará implementado en otro archivo de código.

 

public partial class SaludoPersona
{  
	//Implementación del método parcial. Aquí añadimos el código al método parcial antes definido.  
	partial void SaludarConNombre(string nombre)  
	{    
		Console.WriteLine(nombre);  
	}  
 
	public void SaludoIngles(string nombre)  
	{    
		Console.WriteLine("Hello {0}", nombre);  
	}
}

 

Como pedemos observar en una parte del código solo tenemos la definición del método parcial, no está implementado, es decir, no tiene cuerpo. En el segundo archivo de código tenemos la implementación del método parcial. Aquí es donde se ha escrito lo que hará el método.

Supongamos que tenemos dos equipos de desarrollo en distintas ciudades o paises. A un equipo se le ordena implemantar la primera parte de la clase parcial. Este programador solo sabe que tiene que definir un método parcial en su parte de la clase y después llamarlo. No sabe, ni tiene porque saber, que hace realmente el método. Al segundo equipo de desarrollo se le encarga la implementación del método además del resto del código de su clase parcial.

¿Pero que sucede si no realizamos la implemenación del método en la segunda parte de la clase?. En este caso, el compilador eliminará la definición del método y todas las llamadas en tiempo de compilación del ensamblado final de la clase. Es decir, que no se produce un error en tiempo de ejecución porque no existirá el método realmente. Por lo tanto, la implementación del código de un método parcial no es obligatoria, es opcional.

En el simple ejemplo de antes, se puede haber decidido que no se implemente el código por el momento. Pero se prevee que será utilizado en un futuro. En consecuencia, el primer equipo no tiene que rectificar su código, porque el compilador eliminará la definición y la llamada al método parcial.

Los métodos parciales son normalmente utilizados en situaciones en los que una clase es generada automaticamente por una herramienta y está debe permitir que el programador personalize la funcionabilidad de la clase. Por este motivo la herramienta tan solo definirá los métodos parciales. Luego será el programador el que le de "caracter" al método con su código personal.

Consideraciones que debemos tener en cuenta sobre este tipo de métodos:

  • El método siempre debe devolver void.
  • Pueden tener parámetros de tipo ref, pero no de tipo out.
  • Son implícitamente private, por lo tanto no admiten modificadores de accesibilidad. 
  • Pueden tener modificadores static y unsafe. 
  • No se puede crear un delegado para un método parcial.

 


Tags:
Categories: Lenguajes
Posted by Oscar.SS on lunes, 24 de agosto de 2009 13:53
Permalink | Comentarios (0) | Post RSSRSS comment feed

Método Parse() o los métodos de la clase Convert

Vamos arrogar un poco de luz sobre las diferencias entre utilizar el método Parse() de las estructuras de tipos de .NET o utilizar los métodos de la clase System.Convert. En realidad parece que hacen lo mismo pero existe una gran diferencia.

Suponamos que dejamos que un usuario introduzca un valor númerico por pantalla y queremos realizar calculos con ese valor. Por lo tanto, el valor introducido por el usuario será del tipo System.String y deberemos convertirlo a un tipo de valor numérico, por ejemplo System.Int32.

En definitiva queremos saber que diferencia hay entre ejecutar estas dos lineas de código:

int valorA Convert.ToInt32(valorUsuario);
int valorB Int32.Parse(valorUsuario);

Cuando utilizamos la segunda opción, el método Parse(), si el usuario no ha introducido ningún valor (null) recibiremos una excepción del tipo System.FormatException. Lo que indica que el formato del argumento no cumple las especificaciones del parámetro del método invocado.

En cambio, cuando utilizamos la primera opción, los métodos de la clase System.Convert, si el valor pasádo al método es null, el método ConovertToInt32() devolverá un valor numérico, devolverá cero en todos los casos que el valor de entrada sea null.

Utilizando la herramienta Reflector podemos ver las diferencias de código que hay entre estas dos formas de convertir los tipos de .NET.

 

  • Convert.ToInt32();
public static int ToInt32(string value)
{
     
if (value == null)
     {
          
return 0;
     
}
     
return int.Parse(value, CultureInfo.CurrentCulture);
}
 
  • Int32.Parse();
public static int Parse(string s)
{
     
return Number.ParseInt32(s, NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
}

 


Tags:
Categories: Lenguajes
Posted by Oscar.SS on viernes, 24 de abril de 2009 22:44
Permalink | Comentarios (0) | Post RSSRSS comment feed

Métodos extensores

Los métodos extensores o métodos de extensión, son un tipo especial de métodos estáticos que se utilizan para añadir funcionalidad a otros tipos sin utilizar la herencia o el polimorfismo.

Aunque en principio los métodos extensores más comunes son los que se utilizan con los operadores de consulta estándar de LINQ, podemos también añandir funcionalidad a tipos sellados (sealed) o a tipos propios de .NET de los cuales no conocemos el código que los implementa.

Veamos cual es la sintaxis de los métodos de extensión:

 

   public static class NombreClaseContenedora
   {
      
public static ValorDevuelto NombreMetodoExtensor(this tipo argumento, parámetros)
      {
         
//Código del método extensor.
      
}
   }

Como podemos apreciar el método extensor es estático y está implementado en una clase también estática. Es importante mendionar que ambos, la clase y el método, deben tener el mismo modificador de accesibilidad, en este caso public. No tendría sentido poder acceder desde el código cliente a la clase y no poder hacerlo al método, por ejemplo.

Veamos un ejemplo práctico. Supongamos que tenemos que multiplicar una cantidad introducida por un usuario desde un TextBox y retornar el resultado a otro campo de texto. Es evidente que esto no tiene ninguna dificultad y que podríamos hacerlo con una función de las de siempre pero...veamos el ejemplo y luego entramos en los detalles.

 

   public static class ClaseExtensora
   {
      
public static string MultiplicarXDos(this string arg)
      {
         
int valor Convert.ToInt32(arg);
         
valor *2;
         return 
valor.ToString();
      
}
   }

El primer parámetro de MultiplicarXDos() especifica en qué tipo actúa el método y va precedido del modificador this. En este caso el método actua sobre los tipos System.String de .NET. Esto quiere decir que a partir de este momento, cualquier variable de tipo cadena que definamos en nuestro código tendrá añadido un método MultiplicarXDos().






A pesar de ser un método estático, la llamada al mismo se efectúa como si se tratase de un método de instancia en el tipo extendido. Para poder llamar al método, es necesario que el espacio de nombres en el que esta definida la clase contenedora del método extensor, esté explicitamente importada utilizando una directiva using. Es decir, que para utilizar este método extensor desde otro proyecto deberemos declarar un using EspacioDeNombres.

Como ya se ha comentado, el primer parámetro del método solo indica el tipo al que se le agrega el método. Si queremos podemos añadir tantos parámetros "normales" como queramos. A condición de que el primer parámetro siempre sea el que hace referencia al tipo extendido.

      public static string MultiplicarXDos(this string arg, int multiplicador)
      {
         
int valor Convert.ToInt32(arg);
         
valor *multiplicador;
         return 
valor.ToString();
      
}

A continuación os comento alguanas cosas que hay que tener en cuenta de los métodos de extensión:

  • Puede utilizar métodos de extensión para extender una clase, interfaz, enumerado, estructura, etc.
  • Los métodos de extensión no pueden tener acceso a las variables privadas del tipo que extienden.
  • En tiempo de compilación, los métodos de extensión siempre tienen menos prioridad que los métodos de instancia definidos en el propio tipo. Es decir, que nunca se llamará a un método de extensión que tenga el mismo nombre y firma que un método de la clase que extiende.
  • Y comentar una última cosa, la clase contenedora de los métodos extensores debe ser una clase de nivel superior. Es decir, no puede ser una clase anidada dentro de otra clase.


Tags:
Categories: Lenguajes
Posted by Oscar.SS on lunes, 26 de enero de 2009 23:34
Permalink | Comentarios (3) | Post RSSRSS comment feed

Indexación

Antes de comenzar hablar directamente de los indizadores, vamos a ver unos ejemplos que nos ayudarán a comprender mejor las ventajas del uso de la indexación.

Supongamos que tenemos una clase llamada “Personas” que lo único que hace es guardar los nombres de distintas personas. Parece lógico que para implementar esta clase definamos una matriz de tipo String que almacene los nombres. Por ejemplo podríamos pensar en hacer esto:


    class Personas
    {
        
public string[] Nombre = new string[3];
    
}

Así tenemos definida una clase que almacena 3 nombres de personas en una matriz de tipo String. Para utilizar solo tendríamos que hacer esto:


static void Main(string[] args)
       {
           Personas persona 
= new Personas();
           
//Rellenamos la matriz.
            
persona.Nombre[0"Mariano";
           
persona.Nombre[1"Pedro";
           
persona.Nombre[2"Maria";

           
//Mostrar el contenido de la matriz.
            
foreach (string item in persona.Nombre)
               Console.WriteLine(item)
;

           
Console.ReadLine();
       
}

Desde luego esto funciona pero al tener declarada la matriz como pública no contribuimos a proteger debidamente los miembros de la clase.

Una solución a este problema de proteger los miembros es declararlos como privados. Es decir:


    class Personas
    {
       
private string[] Nombre = new string[3];
    
}

¿Cómo accedemos ahora a los elementos de la matriz “persona”?. Al estar declarada como privada no tenemos acceso a este campo por medio de un objeto de la clase “Personas”.

La solución es muy sencilla. Añadimos a nuestra clase dos métodos públicos, una para asignar nombres en la matriz (método Añadir) y otro para recuperar los valores de los elementos almacenados en la matriz (método Obtener).


    class Personas
    {
        
private string[] Nombre = new string[3];

        public void 
Añadir(string nom, int i)
        {
            Nombre[i] 
nom;
        
}

        
public string Obtener(int i)
        {
            
return Nombre[i];
        
}
    }

Ahora la clase podemos utilizarla por medio de los métodos de la siguiente forma.


            Personas persona = new Personas();
            
//Rellenamos la matriz.
            
persona.Añadir("Mariano"0);
            
persona.Añadir("Pedro"1);
            
persona.Añadir("Maria"2);

            
//Mostrar el contenido de la matriz.
            
for (int 0i < 3i++)
                Console.WriteLine(persona.Obtener(i))
;

            
Console.ReadLine();

Es perfecto. Todo funciona correctamente y tenemos el nivel de protección que deseábamos.

Sin embargo no estamos utilizando la matriz como si fuera una matriz. No accedemos a los elementos por medio de un índice dentro del operador de indexación [] que tantas veces hemos visto en las matrices. Hagamos lo siguiente:


    class Personas
    {
        
private string[] Nombre = new string[3];

        public string this
[int i]
        {
            
get return Nombre[i]}
            
set { Nombre[i] = value; }
        }
    }

La forma de utilizar un objeto de clase “Personas”, ahora que ya esta indexada, es la siguiente:


            Personas persona = new Personas();
            
//Rellenamos la matriz.
            
persona[0"Mariano";
            
persona[1"Pedro";
            
persona[2"Maria";

            
//Mostrar el contenido de la matriz.
            
for (int 0i < 3i++)
                Console.WriteLine(persona[i])
;

            
Console.ReadLine();

Como vemos la definición de la clase tiene mucho menos código al no tener que implementar dos métodos, esto ya es una ventaja. La forma de obtener y establecer los elementos de la matriz es mucho más natural.

Si una propiedad es una especie de “método inteligente” de las variables definidas en una clase. La indexación es “método inteligente” de las matrices definidas en nuestras clases.

No lo dudéis, si tenéis una clase con varios campos que almacenan datos en matrices, ¡indexar la clase!.

 


Tags:
Categories: Lenguajes
Posted by Oscar S.S. on sábado, 26 de abril de 2008 4:27
Permalink | Comentarios (0) | Post RSSRSS comment feed

Array de parámetros opcionales

Aquí tenemos un pequeño y sencillo ejemplo de cómo pasarle a un mismo método diferentes matrices con longitudes diferentes. Al definir los parámetros del método como params podemos tener un mismo método (con diferentes llamadas) que ejecute operaciones con diferentes longuitudes de matrices.

 

    class Params
    {
        
static void Main(string[] args)
        {
            
//Creamos dos matrices con longuitudes distintas.
            
byte[] pares = new byte[4] { 246};
            byte
[] impares = new byte[5] { 1357};

            
//Llamamos al mismo método Mostrar() pasandole como argumento
            //matrices con diferente longitud y una serie numérica.

            
Console.WriteLine("Matriz de pares");
            
Mostrar(pares);

            
Console.WriteLine("\nMatriz de impares");
            
Mostrar(impares);

            
Console.WriteLine("\nSerie numérica");
            
Mostrar(234354657645342334);

            
Console.ReadLine();
        
}

        
static void Mostrar(params byte[] mtzArgs)
        {
            
foreach (byte in mtzArgs)
                Console.WriteLine(i.ToString())
;
        
}
    }

 

La salida de consola es la siguiente:

 


Tags:
Categories: Lenguajes
Posted by Oscar S.S. on viernes, 29 de febrero de 2008 17:36
Permalink | Comentarios (0) | Post RSSRSS comment feed

Cambiar el tamaño de una matriz.

El propósito de este código es mostrar cómo se cambia el tamaño de una matriz en C#.

Antes de seguir con el código, es necesario tener conocimientos previos sobre declaración e inicialización de matrices, así como de los métodos y propiedades de la clase Array. Aquí os dejo unos links de la documentación MSDN:

1- Declarar e inicializar matrices.

2- Utilizar Foreach en matrices.

3- Métodos y propiedades de la clase Array.

En realidad cambiar el tamaño de una matriz no tiene mucho misterio. Supongamos una matriz de tipo int llamada miMatriz:

int[] miMatriz = { 1, 2, 3 };

Supongamos ahora que queremos ampliarla en 4 elementos, es decir, conseguir una matriz de 7 elementos. Es muy sencillo:

miMatriz = new int[miMatriz.Length + 4];

Todo correcto. Ahora tenemos una matriz de tipo int llamada miMatriz que puede contener 7 elementos. Pero ahora vienen las preguntas:

¿Qué ha ocurrido con los datos de la matriz original { 1, 2, 3 }?.

¿La nueva matriz contiene los datos originales?.

La respuesta es que los datos originales { 1, 2, 3 } se han perdido al obtener una nueva matriz de 7 elementos “vacios”, es decir, la nueva matriz contiene { 0, 0, 0, 0, 0, 0, 0 }. Veámoslo en el código.

 

using System;
using 
System.Collections.Generic;
using 
System.Text;

namespace 
ConsoleApplication1
{
    
class Program
    {
        
static void Main(string[] args)
        {
            
// Declarar e inicilizar una matriz de tipo int
            
int[] miMatriz 12};

            
// Mostrar el contenido de MiMatriz
            
Console.WriteLine("Esta es miMatriz original...");
            foreach 
(int in miMatriz)
                Console.WriteLine(x)
;

            
Console.WriteLine();

            
// Ampliamos miMatriz y mostramos su contenido
            
miMatriz = new int[miMatriz.Length + 4];
            
Console.WriteLine("Esta es miMatriz ampliada...");
            foreach 
(int in miMatriz)
                Console.WriteLine(x)
;

            
Console.ReadLine();
        
}
    }
}

 

Como podemos observar los datos de la matriz se han perdido. ¿Qué debemos hacer para ampliar una matriz en C# sin perder los datos?. La única forma de conseguirlo es creando una copia de la matriz que queremos ampliar. Para clarificarlo sigamos estos 4 pasos:

PASO 1. Declarar e inicializar una matriz “de copia” con el mismo tamaño que la matriz original.

PASO 2. Copiar el contenido de la matriz original en la matriz “copia”.

PASO 3. Aumentar el tamaño de la matriz original.

PASO 4. Copiar el contenido de la matriz “copia” en la matriz original ya ampliada.

Veamos el código de estos 4 pasos.

 

class Program
    {
        
static void Main(string[] args)
        {

            
// Declarar e inicilizar una matriz de tipo int
            
int[] miMatriz 12};

            
// Mostrar el contenido de MiMatriz
            
Console.WriteLine("Esta es miMatriz original...");
            foreach 
(int in miMatriz)
                Console.WriteLine(x)
;

            
Console.WriteLine();

            
// PASO 1:
            // Declarar e inicializar una matriz llamada Micopia
            
int[] miCopia = new int[miMatriz.Length];

            
// PASO 2:
            // Copiar el contenido de miMatriz en miCopia
            
miMatriz.CopyTo(miCopia, 0);

            
// PASO 3:
            // Cambiar el tamaño de miMatriz (en este caso lo aumentamos en 4)
            
miMatriz = new int[miMatriz.Length + 4];

            
// PASO4:
            // Copiar el contenido de miCopia en miMatriz ya ampliada
            
miCopia.CopyTo(miMatriz, 0);

            
// Mostrar el contenido de miMatriz ampliada
            
Console.WriteLine("Esta es miMatriz ampliada...");
            foreach 
(int in miMatriz)
                Console.WriteLine(x)
;

            
Console.ReadLine();

        
}
    }
De esta forma obtenemos una matriz ampliada conservando los datos pero en definitiva este comportamiento es muy pobre. Es recomendable trabajar con ArrayList.

Tags:
Categories: Lenguajes
Posted by Oscar S.S. on viernes, 18 de enero de 2008 16:59
Permalink | Comentarios (0) | Post RSSRSS comment feed