generics – T是一个数字?

我试图想出一个方法来创build一个通用类的数字types只做一些计算。

是否有一个我所缺less的所有数字types(int,double,float …)的通用接口?

如果不是的话,那么创build这样一个class级的最好方法是什么?

更新:

我试图达到的主要目的是检查T型的两个variables之间的谁是更大的。

你使用的是什么版本的.NET? 如果你正在使用.NET 3.5,那么我在MiscUtil (free等)中有一个通用的运算符实现 。

这有像T Add<T>(T x, T y)和其他变体在不同types(如DateTime + TimeSpan )上的算术。

此外,这适用于所有内置,解除和定制的操作员,并caching代表的performance。

为什么这是棘手的一些额外的背景是在这里 。

你也可能想知道, dynamic (4.0)sorting也间接解决了这个问题 – 即

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

重新评论一下< / > – 你实际上并不需要操作符。 您只需:

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

有一些数字types的操作接口,如IComparable<T>IConvertibleIEquatable<T>接口。 您可以指定获取特定的function:

 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; } } 

您可以使用委托来扩展具有types特定操作的类:

 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; } } 

用法:

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

您也可以将代理存储在类中,并使用不同的工厂方法为特定的数据types设置代理。 这样的types特定的代码只在工厂的方法。

你不能这样做,因为你必须使用一个接口进行算术运算。 连接上有很多要求为这个特定的目的添加一个IArithmetic接口,但是到目前为止他们都被拒绝了。

你可以通过定义一个没有成员的结构来实现“计算器”界面。 我们在Pluto Toolkit中的插值generics类中采用了这种方法。 举一个详细的例子,我们在这里有一个“向量”计算器的实现,它可以让我们的通用插补器与向量一起工作。 漂浮物,双打,四元数等类似的

你最近得到的是结构我害怕。 您必须对代码中的数字types进行更广泛的检查。

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

在框架BCL(基类库)中,许多数值函数(如System.Math中的函数)通过​​为每个数值types重载来处理这个问题。

BCL中的静态Math类包含静态方法,您可以调用它们而无需创build类的实例。 你可以在class上做同样的事情。 例如,Math.Max有11个重载:

 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>(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); } } } } 

我不相信你可以定义使用generics约束。 您的代码可以在内部检查您的要求,可能使用Double.Parse或Double.TryParse来确定它是否是数字 – 或者如果VB.NET不是问题,那么您可以使用IsNumeric()函数。

编辑:您可以添加对Microsoft.VisualBasic.dll的引用,并从c#调用IsNumeric()函数

你不能在编译时只做。 但是你可以加上更多的限制来清除你的数字types中的大部分“坏types”,如下所示

class yourclass <T>其中T:IComparable,IFormattable,IConvertible,IComparabe <T>,IEquatable <T>,struct {…最后,您仍然必须在运行时检查您的types是否可以使用object.GetType( ) 方法。

如果只是比较,那么IComparable <T>本身就是个诀窍。