Mostrando entradas con la etiqueta Capítulo2. Mostrar todas las entradas
Mostrando entradas con la etiqueta Capítulo2. Mostrar todas las entradas

martes, 2 de julio de 2013

Conversiones en C#

Tabla de Contenido

0. Introducción
1. Conversión en C#
2. Conversión Implícita
3. Conversión Explícita
4. Contraste de Tipos de Conversión
5. Consideraciones Finales
6. Conclusiones
7. Palabras Clave
8. Literatura & Enlaces

0. Introducción

Los principios de ingeniería de software a los que debe someterse un lenguaje de programación involucran la capacidad de conversión de tipos de datos compatibles (predefinidos y personalizados). C# no se queda atrás y permite este tipo de operaciones básicas. En este artículo haremos un repaso rápido de conversión de tipos de datos y descubriremos las dos clases de conversión disponibles en el lenguaje: implícita y explícita.

1. Conversión en C#

El proceso de conversión involucra la tarea de crear un nuevo valor a partir de uno ya existente. El valor que se desee convertir puede ser una literal, por ejemplo, 5.0, "Hola Mundo", 'H' o el valor contenido en un identificador de un tipo específico, e.g., miVariable, miObjeto, fechaActual. Es un proceso que resulta sencillo pero que depende de reglas establecidas en las clases de conversiones (implícita y explícita) que pueden ocurrir.
Clases de conversión en C#
Figura 1. Clases de conversión en C#.

2. Conversión Implícita

La conversión implícita consiste en convertir un tipo de dato a su representación equivalente en otro tipo de dato compatible. Este tipo de conversión no requiere que especificamos ninguna construcción (palabras reservadas, funciones) de C# para que el compilador la lleve a cabo; basta con especificar los valores, variables, llamadas a funciones, etc., dentro de la expresión, para que de esta forma se asigne el valor de la evaluación en la variable, constante, argumento de función.

A continuación se muestra un ejemplo sencillo de esta clase de conversión:

int x = 12345; // int es un entero de 32 bits
long y = x; // Conversión implícita a entero de 64 bits

Debido a la doble capacidad que ofrece el tipo de dato predefinido long, la conversión se lleva a cabo sin ningún problema.

Según [1], las conversiones implícitas se realizan cuando las dos siguientes condiciones son verdaderas:
  • El compilador garantiza que las conversiones se lleven a cabo de manera satisfactoria.
  • No hay pérdida de información.

3. Conversión Explícita

La conversión explícita consiste en convertir tipos de datos con la especificación explícita del tipo de dato destino de la conversión.

Veamos el siguiente ejemplo para hacer una distinción inmediata:

int x = 12345; // int es un entero de 32 bits
long y = x; // Conversión implícita a entero de 64 bits
short z = (short)x; // Conversión explícita a entero de 16 bits

Observemos que para la segunda conversión, short z = (short)x;, fue necesario especificar de forma explícita (short)x antes de asignar el valor de la variable x a z (tipo short).

Finalmente, para realizar una conversión explícita se debe cumplir las dos siguientes condiciones:
  • El compilador no garantiza que la conversión siempre sea satisfactoria.
  • Puede ocurrir pérdida de información durante la conversión.

4. Contraste de Tipos de Conversión

Ahora veamos este ejemplo utilizando variables tipo por referencia para entender el comportamiento de los tipos de conversión:

Perro p1 = new Perro("Tony");
Animal a = p; // Conversión implícita
Perro p2 = (Perro)a; // Conversión explícita

Debido a la relación de que un perro es un animal podemos hacer la conversión implícita (Animal a = p;), mientras que no es posible la relación inversa un animal es un perro, entonces se recurre al modo de conversión explícito en: Perro p2 = (Perro)a;.

5. Consideraciones Finales

A diferencia de la conversión implícita, la conversión explícita requiere del uso del operador de casting.

Por otro lado, debemos tener en cuenta los siguientes eventos durante el proceso de compilación y el uso de genéricos en conversiones:
  • Según [1]: Si el compilador determina que una conversión siempre fallará, ambas clases de conversiones son prohibidas.
  • Ídem [1]:  En conversiones que involucren genéricos (más adelante exploraremos varios artículos acerca de este tema) se pueden generar problemas de conversión en ciertas circunstancias.

6. Conclusiones

Hemos visto cómo hacer algunas conversiones de tipos (int a long) sencillas. Exploramos y explicamos las clases de conversiones implícita e implícita, junto con ejemplos básicos. Al final, resaltamos algunas consideraciones acerca del uso de conversiones en artículos C# que veremos más adelante.

7. Palabras Clave

  • Cast
  • Compilador
  • Conversión explícita
  • Conversión implícita
  • Tipo de dato

8. Literatura & Enlaces

[1] C# 5.0 in a Nutshell by Joseph Albahari and Ben Albahari. Copyright 2012 Joseph Albahari and Ben Albahari, 978-1-449-32010-2.
[2] Casting and Type Conversions (C# Programming Guide) - http://msdn.microsoft.com/en-us/library/ms173105.aspx
V

lunes, 1 de julio de 2013

Tipos de Datos Básicos en C# - Parte 2

Tabla de Contenido

0. Introducción
1. Miembros de un Tipo de Dato
2. Simetría de Tipos de Datos Predefinidos y Personalizados
3. Constructores e Instanciación
4. Miembros de Instancia vs Miembros Estáticos
5. La Palabra Clave public
6. Conclusiones
7. Palabras Clave
8. Referencias

0. Introducción

Cada lenguaje de programación compatible con la CLR cuenta con un conjunto de tipos predefinidos (Tipos Básicos en C# - Parte 1) y otros incluidos en las librerías de NET. Framework. En esta ocasión, además, manejaremos los conceptos de miembros de instancia y miembros estáticos, cuando definamos nuestros propios tipos de datos o utilicemos tipos del Framework (i.e., Console).

Para la introducción del concepto de tipos de datos personalizados recurriremos a la clase ConvertidorUnidades:

Archivo C# ConvertidorUnidades.cs [Enlace alternativo][Enlace alternativo]:

De este código fuente C# exploraremos sus miembros integrantes, como:
  • Campo miembro, 
  • Función miembro.
Desde luego también será importante que entendamos su función para el diseño e implementación de tipos de datos personalizados.

1. Miembros de un Tipo de Dato

El programador tiene la posibilidad de crear sus propios tipos de datos. Cada tipo de dato está compuesto por miembros de tipo. Estos miembros de tipo pueden ser funciones o datos. Por ejemplo, en la clase ConvertidorUnidades, el campo unidades representa un campo miembro, por otro lado, Convertir es una función miembro para esa clase. También hay que tener en cuenta que el constructor (ConvertidorUnidades) de la clase se considera una función miembro.

Los miembros del tipo ayudan a definir la estructura del tipo de dato; por lo cual, tenemos la posibilidad crear miembros (por ejemplo, campos, funciones (métodos, eventos, propiedades), entre otros) según sea necesario para modelar una entidad del mundo del problema (o dominio).

2. Simetría de Tipos de Datos Predefinidos y Personalizados

El concepto práctico de simetría [1] de tipos de datos predefinidos se entiende así en código fuente C#: 

int i = 42;
Console.WriteLine(i.ToString()); // invocación de ToString sobre una variable tipo int


Lo mismo ocurre con tipos de datos integrados; como es el caso de la estructura DateTime de la BCL de .NET Framework:

DateTime d = DateTime.Now;
Console.WriteLine(d.ToString()); // invocación de ToString sobre DateTime

Observe que el sistema de unificación de tipos de C# es el que permite este aspecto simétrico del lenguaje. A nivel de miembros la simetría reside en datos de instancia que guardan el estado del objeto y las funciones miembro que modifican/obtienen el estado. Lo anterior ocurre para ambos tipos (i.e. predefinidos y personalizados).

[Nota: Gracias a la aclaración del concepto de simetría [5] por Jon, a mi pregunta en StackOverflow.]

3. Constructores e Instanciación

Siempre que queramos crear datos y usarlos a partir de un tipo de dato, debemos crear una instancia con la invocación a un constructor (si es requerido, hemos de especificar datos de inicialización). Un ejemplo de este proceso se ve en:

ConvertidorUnidades piesAPulgadasConvertidor = new ConvertidorUnidades(12);
ConvertidorUnidades millasAPiesConvertidor = new ConvertidorUnidades(5820);

La creación e inicialización de un objeto de un tipo de dato, ocurre con la especificación del tipo (ConvertidorUnidades), un identificador (e.g., piesAPulgadasConvertidor), el operador de asignación (=), el operador new [3], y el constructor  del tipo de dato (para el caso, ConvertidorUnidades(int)). Existe una diferencia sutil entre la creación de objetos de tipos de datos integrados: no es necesario que usemos el operador new:

int i = 42;
double pi = 3.14159215;
char c = 'z';
bool b = true;

3.1 Acerca de Constructores

Los constructores son un tipo de método especial, debido a que a diferencia de un método de definición de comportamiento, los constructores no requieren de la especificación de un tipo de retorno. Observemos la definición del constructor ConvertidorUnidades:

public ConvertidorUnidades(int unidadesConversion) // Constructor
{
unidades = unidadesConversion;
}

Una clase puede tener el número de constructores necesarios para cumplir con el diseño del tipo de dato en cuestión. Además, los constructores pueden ser sobrescritos (este tema lo veremos con más detalle en publicaciones posteriores).

[Nota: Más acerca de constructores en [6].]

4. Miembros de Instancia vs. Miembros Estáticos

Tanto los datos miembro como las funciones miembro de una instancia se conocen como miembros de instancia. Si vemos en ConvertidorUnidades, esta clase cuenta con una función miembro llamada Convertir y un dato miembro llamado unidades. En su defecto, los miembros de una clase son miembros de instancia, como en los casos anteriores. En caso contrario, si especificamos explícitamente en la declaración la palabra clave static, el miembro es estático.

Para ejemplificar el uso de miembros estáticos, recurramos a .NET Framework. La clase Console es una clase estática y todos miembros tienen esa misma propiedad: Console.WriteLine() es un ejemplo de método estático que reside en la clase Console.

Para contrastar, utilicemos el siguiente ejemplo.


En este código cliente creamos dos instancias (objetos) del tipo de dato personalizado Panda, con lo cual podremos demostrar el uso de miembros estáticos.

Archivo C# Panda.cs [Enlace alternativo][Enlace alternativo]:

En la primera invocación al campo Panda.Poblacion, en la línea 10, el valor que se mostrará en pantalla será 1; esto debido a que por cada objeto Panda que se cree el campo se incrementará en una unidad: Poblacion = Poblacion + 1; (línea 10 en la clase Panda). En la siguiente invocación a Panda.Poblacion en pantalla aparecerá 2. Esto será ocurriendo de forma incremental cada vez que invoquemos a Panda.Poblacion.

5. La palabra Clave public

La palabra clave public [4] permite exponer miembros (datos o funciones) a clases cliente. La clase Panda tiene dos datos miembro con esta clasificación: Nombre y Poblacion. El constructor también es public.

En términos de programación orientada a objetos, los miembros públicos se encargan de encapsular los miembros privados de la clase, y en consecuencia, aislar el funcionamiento interno de la definición del tipo de dato.

6. Conclusiones

Hemos entendido el concepto de datos y funciones miembros como elementos formadores de una estructura . Hemos apreciado el factor de simetría entre tipos de datos predefinidos y personalizados. También vimos el concepto de miembros estáticos, útiles para compartir comportamiento y datos entre instancias (objetos) de un mismo tipo de dato. Para culminar, revisamos, en breve, el uso de la palabra public para encapsular el funcionamiento interno de un tipo de dato.

7. Palabras Clave

  • Constructor
  • Dominio del problema
  • Encapsular
  • Función
  • Método
  • Miembro
  • Mundo del problema
  • Programación orientada a objetos
  • Tipo de dato
  • Tipo de retorno

8. Referencias

[1]: C# 5.0 in a Nutshell by Joseph Albahari and Ben Albahari. Copyright 2012 Joseph Albahari and Ben Albahari, 978-1-449-32010-2.
[2]: Members - http://msdn.microsoft.com/en-us/library/vstudio/ms173113.aspx
[3]: new Operator - http://msdn.microsoft.com/en-us/library/fa0ab757.aspx
[4]: public - http://msdn.microsoft.com/en-us/library/ms173121(v=vs.80).aspx
[5]: What does mean “symmetry” between predefined types and custom types? - http://stackoverflow.com/questions/17374867/what-does-mean-symmetry-between-predefined-types-and-custom-types
[6]: An Intro to Constructors in C# - http://www.codeproject.com/Articles/7011/An-Intro-to-Constructors-in-C
V

jueves, 19 de noviembre de 2009

Ch02-31: Cuadrados y Cubos

2.26 "Utilizando sólo las técnicas de programación que aprendió en este capítulo, escriba una aplicación que calcule los cuadrados y cubos de los números del 0 al 10, y que imprima los valores resultantes en formato de tabla, como se muestra a continuación. [Nota: Este programa no requiere de ningún tipo de entrada por parte del usuario]."



Solución:

Código Java CuadradoCubo.java [enlace alternativo]:

Conclusiones:


El uso de los especificadores de formato proporcionan un medio idóneo para mostrar información tabulada.

Los paréntesis redundantes, es decir, signos de agrupación que ayudan a identificar de forma fácil y directa el resultado que se pretende obtener a través de la expresión.