La Escuela del Programador

 

Métodos Genéricos con Operaciones

Como usted puede ver en el artículo publicado hace años en el sitio www.codeproject.com, llamado Using generics for calculations, alli se muestra que por ese entonces y durante mucho tiempo, realizar cálculos u operaciones con tipos genéricos no era tan fácil como parecía ser. Esto se debía basicamente a que en .NET, por ese entonces y hasta al advenimiento de los tipos dinámicos, los parámetros de tipo sin restricciones eran asumidos del tipo System.Object, el que no definía operadores (+, *, etc). Sin embargo, a partir del .NET Framework 4, los tipos dinámicos permiten facilmente hacer esto.

Supongamos que queremos crear un método que tome un número, y devuelva su cuadrado, pero deseamos hacerlo de una manera que el mismo método nos permita utilizar diferentes tipos numéricos como parámetro y que devuelva algún otro tipo (por ejemplo pasar un byte y devolver un int, o pasarle un double y devolver un double, etc)

Ahora con el adevenimiento de los tipos dinámicos es fácil hacer esto. Veremos un programa sencillo que les demostrará esto:

Código en C#:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
static class Program
{
    public static void Main()
    {
        long a = 100000;
        Console.WriteLine("El cuadrado de {0:0,0} es {1:0,0}", 
                              a, Cuadrado<long, long>(a));

        double b =200.50;
        Console.WriteLine("El cuadrado de {0:0,0.00} es {1:0,0.00}", 
                              b, Cuadrado<double, double>(b));

        byte c = 255;
        Console.WriteLine("El cuadrado de {0:0,0} es {1:0,0}", 
                              c, Cuadrado<byte, int>(c));

        Decimal d = 2000000000;
        Console.WriteLine("El cuadrado de {0:0,0} es {1:0,0}", 
                              d, Cuadrado<Decimal, Decimal>(d));
    }

    public static R Cuadrado<T, R>(dynamic x)
    {
        return x*x;
    }
}

Código en VB

Option Strict Off
Module Module1
    Sub Main()
        Dim a As Long = 100000
        Console.WriteLine("El cuadrado de {0:0,0} es {1:0,0}", 
                              a, Cuadrado(Of Long, Long)(a))

        Dim b As Double = 200.5
        Console.WriteLine("El cuadrado de {0:0,0.00} es {1:0,0.00}", 
                              b, Cuadrado(Of Double, Double)(b))

        Dim c As Byte = 255
        Console.WriteLine("El cuadrado de {0:0,0} es {1:0,0}", 
                              c, Cuadrado(Of Byte, Integer)(c))

        Dim d As [Decimal] = 2000000000
        Console.WriteLine("El cuadrado de {0:0,0} es {1:0,0}", 
                              d, Cuadrado(Of Decimal, Decimal)(d))
    End Sub

    Function Cuadrado(Of T, R)(x As Object) As R
        Return x * x
    End Function
End Module

La salida de este programa es:

Salida del programa que contiene un método genérico 'Function Cuadrado(Of T)(x as T) as R'
Figura 1- Salida del programa que contiene un método genérico 'Function Cuadrado(Of T, R)(x as T) as R'.

 

 

 


En la especificación C# 4.0, section 7.8.1 Operador Multiplicación, se puede comprobar que sólo los siguientes operadores de producto de números enteros están disponibles:
  • int operator *(int x, int y);
  • uint operator *(uint x, uint y);
  • long operator *(long x, long y);
  • ulong operator *(ulong x, ulong y);
En la misma sección también se dice lo siguiente: Los operandos se convierten a los tipos de parámetros del operador seleccionado, y el tipo del resultado es el tipo de retorno del operador. Esto explica el porque, si hacemos la siguiente llamada :

 

 

 

ushort x = 47000;
Console.WriteLine("El cuadrado de {0:0,0} es {1:0,0}", 
                      x, Cuadrado<ushort, long>(x));
...obtenemos el resultado -2,085,967,296 Según lo definido en el apartado mencionado arriba de la especificación C#, el operador * está definido entre operadores int y/o entre operadores long, por lo que al pasarle dos ushort, automáticamente los convierte a enteros y el tipo de retorno será también un int. Como el tipo entero puede tomar valores en el rango -2,147,483,648 a 2,147,483,647 y debido a que 47,000 al cuadrado es 2,209,000,000 y como 2,209,000,000 - 2,147,483,648 = 61,516,352 y -2,147,483,648 + 61,516,352 = -2,085,967,296, lo que explica por qué el resultado es ese.

 

 

 


Por otra parte, en la especificación del lenguaje Visual Basic versión 10, apartado 11.13.5 (Multiplication Operator), se establece que el operador de multiplicación está definido para los siguientes tipos: · Byte, SByte, UShort, Short, UInteger, Integer, ULong, and Long. Por ese motivo al pasarle el mismo código:

 

 

 

 Dim x As UShort = 47000
        Console.WriteLine("El cuadrado de {0:0,0} es {1:0,0}", 
                              x, Cuadrado(Of UShort, Long)(x))
...obtenemos el resultado correcto: 2,209,000,000
respag
Panamá - © 2012
http://respag.net/métodos-genéricos-con-operaciones.aspx