2009-09-03 15 views
6

Quiero escribir un método C# que pueda aceptar cualquier número. Algo así como:C# clase base numérica

public static T Sum(T a, T b) where T : number { // (not real code) 
    return a + b; 
} 

Pero no veo un "número" clase base en C#, como existe en la mayoría de los otros idiomas que he usado. Los tipos de valores numéricos son IComparable, IFormattable, IConvertible, IComparable e IEquatable, pero nada que parezca tener capacidades aritméticas. Son todas estructuras, sin aparente superclase común, aparte del objeto. (Perdóneme si estoy confundiendo el significado aquí, ya que no estoy muy familiarizado con las estructuras de C# y precisamente todas las formas en que son o no como las clases).

Me falta algo, o no es posible escribir un método en C# que haga "a + b" sin declarar exactamente lo que a y b son en el contexto del "+"?

+0

(Respondió para comentar; para aclarar: ** no hay ** fundición ni sobrecarga) –

+0

(con respecto a su otro comentario sobre 'IEnumerable.Sum'; tenga en cuenta que MiscUtil proporciona versiones genéricas de' Suma', 'Promedio' , etc. - usando 'Operator', etc.) –

Respuesta

3

Tendrás que recurrir al uso de la sobrecarga. Un poco como la clase Math está funcionando con una función como Math.Max donde admite todos los tipos numéricos.

El link propuesto por CD también es ingenioso.

+0

O como los métodos de extensión de Linq están haciendo con IEnumerable.Sum e implementan solo la mitad de los tipos numéricos. – Ken

+0

No necesariamente. Hay soluciones genéricas (ver mi respuesta para más información). –

2

Desafortunadamente, no existe tal clase/interfaz.

0

Lo mejor que puede hacer es where T : struct que requiere un ValueType; todos los numéricos son ValueTypes.

Lamentablemente, también lo son todas las estructuras definidas por el usuario, por lo que ese es el inconveniente. No hay un genérico específico que acepte todas las clases numéricas.

que dudan en incluso sugerir esto, pero usted podría considerar controles de tiempo de ejecución en contra del tipo de T en el método y tirar si T no es un int, largo, corto, flotador, o doble. Desafortunadamente, esto no ayudará a un programador en tiempo de compilación.

2

int y los otros tipos numéricos son ValueTypes. Como ya se dijo, todo lo que puede hacer es decir where T: struct. Bueno, podrías usar la reflexión para verificar si el argumento tipo implementa la adición ... pero no estoy seguro de si es una buena idea.

3

Consulte this SO question para una discusión similar.

Además, se puede hacer esto (con un poco de esfuerzo tedioso) si usted está dispuesto a crear tipos separados para cada uno de los tipos de números centrales .Net desea utilizarlo para ...

Cree dos estructuras , llamados say, MyInt y MyDecimal que actúan como fachadas para CTS Int32 y Decimal core types (Contienen un campo interno de ese tipo respectivo). Cada uno debe tener un ctor que tome una instancia del tipo Core CTS como parámetro de entrada ..

hacer que cada uno implementar una interfaz vacío llamado INumeric

Luego, en sus métodos genéricos, MAK e la restricción basada en esta interfaz. A la baja, donde quiera que quiera usar estos métodos, debe construir una instancia del tipo personalizado apropiado en lugar del tipo Core CTS, y pasar el tipo personalizado al método.

NOTA: la codificación de las estructuras personalizadas para emular correctamente todo el comportamiento de los tipos de núcleo CTS es la parte tediosa ... Debe implementar varias interfaces CLR incorporadas (IComparable, etc.) y sobrecargar toda la aritmética, y operadores booleanos ...

0

Esta es una pregunta muy común; si está utilizando .NET 3.5, hay mucho soporte para esto en MiscUtil, a través de la clase Operator, que admite tipos incorporados y cualquier tipo personalizado con operadores (incluidos los operadores "levantados"); En particular, esto permite el uso con genéricos, por ejemplo:

public static T Sum<T>(this IEnumerable<T> source) { 
    T sum = Operator<T>.Zero; 
    foreach (T value in source) { 
     if (value != null) { 
      sum = Operator.Add(sum, value); 
     } 
    } 
    return sum; 
} 

o para otro ejemplo; Complex<T>

+0

Es una especie de ordenada (o grosera) que hay una biblioteca para hacer toda la sobrecarga y el casting para mí, pero no considero que "Operator.Add (a, b)" sea una solución al problema de "a + b "no ser genérico. Si quiero ser genérico escribiendo un montón de código detallado, no necesito una biblioteca de terceros para hacer eso. :-) – Ken

+0

There * is * no overloading ni casting. Es un código genuino basado en genéricos, con algún uso inteligente de Expression para precompilar un delegado (por tipo) que puede hacer la aritmética. –

+0

Podría ayudar si aclaro que 'Agregar' es en realidad un método genérico ('Agregar '); simplemente que en el ejemplo usamos la inferencia de tipo genérico para evitar tener que agregar el ''. Pero todavía está allí. –

Cuestiones relacionadas