2009-08-12 17 views
43

Estoy tratando de encontrar la forma de crear una clase genérica solo para tipos de números, para hacer algunos cálculos.Genéricos: ¿dónde T es un número?

¿Existe una interfaz común para todos los tipos de número (int, doble, flotante ...) que me falta?

Si no, ¿cuál será la mejor manera de crear una clase de este tipo?

ACTUALIZACIÓN:

Lo principal que estoy tratando de lograr es la comprobación que es el más grande entre dos variables de tipo T.

+1

No funcionan en este escenario, pero cuando trabajas con genéricos, es bueno tener en cuenta las "restricciones de tipo genérico". http://msdn.microsoft.com/en-us/library/d5x73970%28VS.80%29.aspx – STW

+1

(respondió al comentario) –

+1

Consulte esta publicación aquí http://stackoverflow.com/questions/32664/c- generic-constraint-for-only-integers – David

Respuesta

28

¿Qué versión de .NET estás usando? Si está utilizando .NET 3.5, entonces tengo un generic operators implementation en MiscUtil (gratis, etc.).

Esto tiene métodos como T Add<T>(T x, T y), y otras variantes para la aritmética en diferentes tipos (como DateTime + TimeSpan).

Además, esto funciona para todos los operadores incorporados, levantados y personalizados, y almacena en caché al delegado para el rendimiento.

Algunos antecedentes sobre por qué esto es complicado es here.

Usted también puede querer saber que dynamic (4.0) clase-de resuelve este problema indirectamente también - es decir

dynamic x = ..., y = ... 
dynamic result = x + y; // does what you expect 

Re el comentario sobre </> - que en realidad no necesidad operadores para esto; solo necesita:

T x = ..., T y = ... 
int c = Comparer<T>.Default.Compare(x,y); 
if(c < 0) { 
    // x < y 
} else if (c > 0) { 
    // x > y 
} 
+1

Estoy usando .NET 3.5, traté de hacer "if (x> y)" mientras que xey de tipo T. –

+1

MiscUtil tiene Operator.GreaterThan, pero ni siquiera necesita esto; se actualizará para mostrar por qué no ... –

6

más cercano que se obtiene es struct me temo. Tendrá que hacer comprobaciones más exhaustivas para los tipos de números en el código.

public class MyClass<T> where T : struct 
(...) 
+6

¿por qué no 'donde T: struct, IConvertible', que está un poco más cerca al menos. – BrainSlugs83

2

No creo que pueda definir eso usando una restricción de tipo genérico. Su código podría verificar internamente sus requisitos, posiblemente utilizando Double.Parse o Double.TryParse para determinar si es un número-- o si VB.NET no está descartado, entonces podría usar la función IsNumeric().

Editar: Puede añadir una referencia a Microsoft.VisualBasic.dll y llamar a la función IsNumeric() de C#

8

No se puede hacer esto, ya que tendría que utilizar una única interfaz para la aritmética operaciones. Ha habido muchas solicitudes en Connect para agregar una interfaz IArithmetic para este propósito específico, pero hasta ahora todas han sido rechazadas.

Puede solucionar este problema definiendo una estructura sin miembros, que implementa una interfaz de "Calculadora". Tomamos este enfoque en una clase genérica de interpolación en el Pluto Toolkit. Para un ejemplo detallado, tenemos una implementación de calculadora "vector" here, que permite que nuestro interpolador genérico funcione con vectores. Hay similares para flotantes, dobles, cuaterniones, etc.

+3

¡este es un enlace roto! – happygilmore

3

En el Framework BCL (biblioteca de clases base), muchas funciones numéricas (como las funciones en System.Math) tratan esto teniendo sobrecargas para cada tipo numérico .

La clase matemática estática en el BCL contiene métodos estáticos, que puede llamar sin tener que crear una instancia de la clase. Podrías hacer lo mismo en tu clase. Por ejemplo, Math.max tiene 11 sobrecargas:

public static byte Max(byte val1, byte val2); 
public static decimal Max(decimal val1, decimal val2); 
public static double Max(double val1, double val2); 
public static short Max(short val1, short val2); 
public static int Max(int val1, int val2); 
public static long Max(long val1, long val2); 
public static sbyte Max(sbyte val1, sbyte val2); 
public static float Max(float val1, float val2); 
public static ushort Max(ushort val1, ushort val2); 
public static uint Max(uint val1, uint val2); 
public static ulong Max(ulong val1, ulong val2); 
12

hay interfaces para algunas de las operaciones sobre los tipos de números, como las interfaces IComparable<T>, IConvertible y IEquatable<T>. Puede especificar que para obtener una funcionalidad específica:

public class MaxFinder<T> where T : IComparable<T> { 

    public T FindMax(IEnumerable<T> items) { 
     T result = default(T); 
     bool first = true; 
     foreach (T item in items) { 
     if (first) { 
      result = item; 
      first = false; 
     } else { 
      if (item.CompareTo(result) > 0) { 
       result = item; 
      } 
     } 
     } 
     return result; 
    } 

} 

se puede utilizar delegados para expandir una clase con operaciones específicas de tipo:

public class Adder<T> { 

    public delegate T AddDelegate(T item1, T item2); 

    public T AddAll(IEnumerable<T> items, AddDelegate add) { 
     T result = default(T); 
     foreach (T item in items) { 
     result = add(result, item); 
     } 
     return result; 
    } 

} 

Uso:

Adder<int> adder = new Adder<int>(); 
int[] list = { 1, 2, 3 }; 
int sum = adder.AddAll(list, delegate(int x, int y) { return x + y; }); 

También puede guardar delegados en la clase, y tienen diferentes métodos de fábrica que configuran delegados para un tipo de datos específico. De esta forma, el código específico del tipo solo está en los métodos de fábrica.

2

No puede hacerlo solo en tiempo de compilación. pero se podía poner más restricciones para eliminar a la mayoría de los 'tipos malos' en su tipo numérico, como a continuación

clase yourclass <T> donde T: IComparable, IFormattable, IConvertible, IComparabe <T>, IEquatable <T>, struct {... Al final todavía tendría que verificar en tiempo de ejecución si su tipo es aceptable usando el método object.GetType().

Si solo comparando, entonces IComparable <T> solo hace el truco.

3
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace GenericPratice1 
{ 
    public delegate T Del<T>(T numone, T numtwo)where T:struct; 
    class Class1 
    { 
     public T Addition<T>(T numone, T numtwo) where T:struct 
     { 
      return ((dynamic)numone + (dynamic)numtwo); 
     } 
     public T Substraction<T>(T numone, T numtwo) where T : struct 
     { 
      return ((dynamic)numone - (dynamic)numtwo); 
     } 
     public T Division<T>(T numone, T numtwo) where T : struct 
     { 
      return ((dynamic)numone/(dynamic)numtwo); 
     } 
     public T Multiplication<T>(T numone, T numtwo) where T : struct 
     { 
      return ((dynamic)numone * (dynamic)numtwo); 
     } 

     public Del<T> GetMethodInt<T>(int ch) where T:struct 
     { 
      Console.WriteLine("Enter the NumberOne::"); 
      T numone =(T) Convert.ChangeType((object)(Console.ReadLine()), typeof(T)); 
      Console.WriteLine("Enter the NumberTwo::"); 
      T numtwo = (T)Convert.ChangeType((object)(Console.ReadLine()), typeof(T)); 
      T result = default(T); 
      Class1 c = this; 
      Del<T> deleg = null; 
      switch (ch) 
      { 
       case 1: 
        deleg = c.Addition<T>; 
        result = deleg.Invoke(numone, numtwo); 
        break; 
       case 2: deleg = c.Substraction<T>; 
        result = deleg.Invoke(numone, numtwo); 
        break; 
       case 3: deleg = c.Division<T>; 
        result = deleg.Invoke(numone, numtwo); 
        break; 
       case 4: deleg = c.Multiplication<T>; 
        result = deleg.Invoke(numone, numtwo); 
        break; 
       default: 
        Console.WriteLine("Invalid entry"); 
        break; 
      } 
      Console.WriteLine("Result is:: " + result); 
      return deleg; 
     } 

    } 
    class Calculator 
    { 
     public static void Main(string[] args) 
     { 
      Class1 cs = new Class1(); 
      Console.WriteLine("Enter the DataType choice:"); 
      Console.WriteLine("1 : Int\n2 : Float"); 
      int sel = Convert.ToInt32(Console.ReadLine()); 
      Console.WriteLine("Enter the choice::"); 
      Console.WriteLine("1 : Addition\n2 : Substraction\3 : Division\4 : Multiplication"); 
      int ch = Convert.ToInt32(Console.ReadLine()); 
      if (sel == 1) 
      { 
       cs.GetMethodInt<int>(ch); 
      } 
      else 
      { 
       cs.GetMethodInt<float>(ch); 
      } 

     } 
    } 
} 
Cuestiones relacionadas