Genéricos – onde T é um número?

Eu estou tentando descobrir uma maneira de criar uma class genérica apenas para tipos de números, para fazer alguns cálculos.

Existe uma interface comum para todos os tipos de números (int, double, float …) que estou perdendo ???

Se não, qual será a melhor maneira de criar essa class?

ATUALIZAR:

A principal coisa que estou tentando alcançar é verificar quem é o maior entre duas variables ​​do tipo T.

Qual versão do .NET você está usando? Se você estiver usando o .NET 3.5, então eu tenho uma implementação de operadores genéricos em MiscUtil (free etc).

Isso tem methods como T Add(T x, T y) e outras variantes para aritmética em diferentes tipos (como DateTime + TimeSpan ).

Além disso, isso funciona para todos os operadores internos, aprimorados e sob medida, e armazena em cache o delegado para desempenho.

Algumas informações adicionais sobre por que isso é complicado estão aqui .

Você também pode querer saber que o tipo dynamic (4.0) resolve esse problema indiretamente também – isto é,

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

Re o comentário sobre < / > - você realmente não precisa de operadores para isso; você só precisa:

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

Existem interfaces para algumas das operações nos tipos de números, como as IComparable , IConvertible e IEquatable . Você pode especificar isso para obter uma funcionalidade específica:

 public class MaxFinder where T : IComparable { public T FindMax(IEnumerable 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; } } 

Você pode usar representantes para expandir uma class com operações específicas de tipo:

 public class Adder { public delegate T AddDelegate(T item1, T item2); public T AddAll(IEnumerable items, AddDelegate add) { T result = default(T); foreach (T item in items) { result = add(result, item); } return result; } } 

Uso:

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

Você também pode armazenar delegates na class e ter diferentes methods de fábrica que configurem delegates para um tipo de dados específico. Dessa forma, o código específico do tipo é apenas nos methods de fábrica.

Você não pode fazer isso, desde que você teria que usar uma única interface para operações aritméticas. Houve muitas solicitações no Connect para adicionar uma interface IArithmetic para esse propósito específico, mas até agora todas foram rejeitadas.

Você pode resolver isso definindo uma estrutura sem membros, o que implementa uma interface “Calculadora”. Usamos essa abordagem em uma class genérica de interpolação no Pluto Toolkit . Para um exemplo detalhado, temos uma implementação de calculadora “vetorial” aqui , que permite que nosso interpolador genérico trabalhe com vetores. Existem outros semelhantes para carros alegóricos, duplos, quaterniões, etc.

O mais próximo que você está é struct eu estou com medo. Você terá que fazer verificações mais extensas para tipos de números no código.

 public class MyClass where T : struct (...) 

No BCL de estrutura (biblioteca de classs base), muitas funções numéricas (como as funções no System.Math) lidam com isso por ter sobrecargas para cada tipo numérico.

A class matemática estática na BCL contém methods estáticos, que você pode chamar sem ter que criar uma instância da class. Você poderia fazer o mesmo na sua aula. Por exemplo, Math.Max ​​tem 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); 
 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace GenericPratice1 { public delegate T Del(T numone, T numtwo)where T:struct; class Class1 { public T Addition(T numone, T numtwo) where T:struct { return ((dynamic)numone + (dynamic)numtwo); } public T Substraction(T numone, T numtwo) where T : struct { return ((dynamic)numone - (dynamic)numtwo); } public T Division(T numone, T numtwo) where T : struct { return ((dynamic)numone / (dynamic)numtwo); } public T Multiplication(T numone, T numtwo) where T : struct { return ((dynamic)numone * (dynamic)numtwo); } public Del GetMethodInt(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 deleg = null; switch (ch) { case 1: deleg = c.Addition; result = deleg.Invoke(numone, numtwo); break; case 2: deleg = c.Substraction; result = deleg.Invoke(numone, numtwo); break; case 3: deleg = c.Division; result = deleg.Invoke(numone, numtwo); break; case 4: deleg = c.Multiplication; 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(ch); } else { cs.GetMethodInt(ch); } } } } 

Eu não acredito que você possa definir isso usando uma restrição de tipo genérico. Seu código pode verificar internamente suas necessidades, possivelmente usando Double.Parse ou Double.TryParse para determinar se é um número – ou se o VB.NET não estiver fora de questão, então você pode usar a function IsNumeric ().

Edit: você pode adicionar uma referência para Microsoft.VisualBasic.dll e chamar a function IsNumeric () de c #

Você não pode fazê-lo apenas em tempo de compilation. Mas você poderia colocar mais restrições para eliminar a maioria dos ‘tipos ruins’ em seu tipo numérico como abaixo

class yourclass onde T: IComparable, IFormattable, IConvertible, IComparabe , IEquatable , struct {… No final, você ainda teria que verificar em tempo de execução se o seu tipo é aceitável usando object.GetType ( ) método.

Se apenas comparando, então IComparable sozinho faz o truque.