Conversiones de tipos personalizadas (VB y C#)

Una de las novedades que introdujo VB.NET en su version 2005 fue la sobrecarga de operadores, hasta entonces exclusiva de C# (siempre hablando de lenguajes .NET).

A pesar del tiempo que ha transcurrido desde que VB.NET soporta la sobrecarga de operadores seguramente será una desconocida para muchos. Resumiendo - muchisimo -, diré que es una caracteristica que nos permite definir como se va a comportar el programa cuando se ejecute un operador (suma, resta ...).

De este forma podríamos tener una clase - Punto2D, con dos coordenadas x, y - y definir que cuando se sumen dos puntos se sumen sus coordenadas. El siguiente ejemplo muestra como se hace:

 

Public Class Punto2D

Public X As Integer

Public Y As Integer

Public Shared Operator +(ByVal punto1 As Punto2D, _

ByVal punto2 As Punto2D) As Punto2D

Dim resultado As New Punto2D

resultado.X = punto1.X + punto2.X

resultado.Y = punto1.Y + punto2.Y

 

Return resultado

 

End Operator

End Class

Cuando se sumen dos instancias de Punto2D, se ejecutará el código definido en el operador, sumando las coordenadas X e Y de cada punto, y retornando una nueva instancia de Punto2D con los valores asignados.

 

Dim p1 As New Punto2D With {.X = 5, .Y = 1500}

Dim p2 As New Punto2D With {.X = 10, .Y = 100}

'Aqui se ejecuta la sobrecarga del operador +

Dim p3 As Punto2D = p1 + p2

 

Console.WriteLine("{0} {1}", p3.X, p3.Y)

Console.ReadLine()

Bien, volvamos ahora al tema principal del articulo - como realizar conversiones de tipos personalizadas -. Otra de las opciones que nos ofrece la sobrecarga de operadores es la de definir como se convierte un tipo en otro.

Vamos a verlo con un ejemplo: tenemos dos clases - Cliente y Empleado - y nuestro objetivo es convertir una instancia de cliente en empleado.

Las clases del ejemplo son las siguientes:

 

Public Class Empleado

 

Private _nombre As String

Public Property Nombre() As String

Get

Return _nombre

End Get

Set(ByVal value As String)

_nombre = value

End Set

End Property

 

Private _apellidos As String

Public Property Apellidos() As String

Get

Return _apellidos

End Get

Set(ByVal value As String)

_apellidos = value

End Set

End Property

 

Private _fechaNacimiento As DateTime

Public Property FechaNacimiento() As DateTime

Get

Return _fechaNacimiento

End Get

Set(ByVal value As DateTime)

_fechaNacimiento = value

End Set

End Property

 

End Class

y la clase Cliente:

 

Public Class Cliente

 

Private _nombre As String

Public Property Nombre() As String

Get

Return _nombre

End Get

Set(ByVal value As String)

_nombre = value

End Set

End Property

 

Private _apellidos As String

Public Property Apellidos() As String

Get

Return _apellidos

End Get

Set(ByVal value As String)

_apellidos = value

End Set

End Property

 

Private _fechaNacimiento As DateTime

Public Property FechaNacimiento() As DateTime

Get

Return _fechaNacimiento

End Get

Set(ByVal value As DateTime)

_fechaNacimiento = value

End Set

End Property

 

End Class

Si intentamos hacer lo siguiente:

 

Dim empleado As New Empleado With _

{.Nombre = "Pedro", _

.Apellidos = "Herrarte", _

.FechaNacimiento = New DateTime(1975, 5, 13)}

Dim cliente As Cliente

cliente = CType(empleado, Cliente)

Obtendremos el siguiente error:

Error 1 Value of type 'ConsoleApplication.Empleado' cannot be converted to 'ConsoleApplication.Cliente'.

Para definir la conversión debemos emplear el siguiente código donde definimos el operador CType .Especial atencion al uso de la palabra clave Narrowing - también podríamos haber usado Widening -, posteriormente explicaré las diferencias.

 

Public Class Cliente

'El cuerpo de la clase cliente ...

Public Shared Narrowing _

Operator CType(ByVal empleado As Empleado) As Cliente

Dim cliente As New Cliente

cliente.Nombre = empleado.Nombre

cliente.Apellidos = empleado.Apellidos

cliente.FechaNacimiento = empleado.FechaNacimiento

Return cliente

End Operator

End Class

Ahora ya podemos ejecutar la conversion anterior.

 

Dim empleado As New Empleado With _

{.Nombre = "Pedro", _

.Apellidos = "Herrarte", _

.FechaNacimiento = New DateTime(1975, 5, 13)}

 

Dim cliente As Cliente

cliente = CType(empleado, Cliente)

 

Console.WriteLine("{0} {1} {2:dd/MM/yyyy}", _

cliente.Nombre, _

cliente.Apellidos, _

cliente.FechaNacimiento)

Console.ReadLine()

Del mismo modo podríamos escribir el código de conversión te tipo en C# - la sintaxis cambia pero no la funcionalidad:

 

class Cliente

{

// ...

public static explicit operator Cliente(Empleado empleado)

{

Cliente cliente = new Cliente();

cliente.Nombre = empleado.Nombre;

cliente.Apellidos = empleado.Apellidos;

cliente.FechaNacimiento = empleado.FechaNacimiento;

return cliente;

}

}

Cuando hemos definido la conversion hemos utilizado la palabra la clave Narrowing.Narrowing indica que la conversion debe realizarse de forma explicita, es decir es necesario usar CType -siempre y cuando "Option Strict" está activado.

 

Dim empleado As New Empleado With ...

Dim cliente As Cliente

cliente = CType(empleado, Cliente)

Widening implica conversion implicita, es decir NO es necesario usar CType de forma que este código sería válido:

 

Dim empleado As New Empleado With ...

Dim cliente As Cliente

cliente = empleado

Como ejercicio de reflexion nos podemos preguntar porque se han utilizado Narrowing Widening en lugar de explicit e implicit como se hace en C#.

Un último apunte, es reconmendable forzar siempre la conversión explicita y tener siempre en cuenta que la conversion de un tipo en otro puede ocasionar la perdida de datos si el rango de destino es inferior al original - ver este enlace http://msdn.microsoft.com/en-us/library/k1e94s7e(VS.80).aspx -, (por ejemplo si convertimos en dato long a integer).

Saludos , DJK

Pedro  Herrarte  Sánchez
Conversiones de tipos personalizadas (VB y C#)
Pedro Herrarte Sánchez

Pedro Herrarte, es consultor independiente, ofreciendo servicios de consultoría, análisis, desarrollo y formación. Posee mas de diez años de experiencia trabajando para las principales empresas de España. Es especialista en tecnologías .NET, entornos Web (ASP.NET, ASP.NET MVC,jQuery, HTML5), bases de datos (SQL Server y ORACLE) e integración de sistemas. Es experto en desarrollo (C#, VB.Net, T-SQL, PL/SQL, , ASP, CGI , C, Pro*C, Java, Essbase, Vignette, PowerBuilder y Visual Basic ...) y bases de datos (SQL Server y ORACLE). Pedro es MCP y MAP 2012, es fundador, diseñador y programador de www.devjoker.com..
Fecha de alta:25/03/2009
Última actualizacion:25/03/2009
Visitas totales:5641
Valorar el contenido:
Últimas consultas realizadas en los foros
Últimas preguntas sin contestar en los foros de devjoker.com