泛型-其中 T 是一个数字?

我试图找到一种方法来创建一个泛型类,仅用于数字类型,用于进行一些计算。

对于所有数字类型(int、 double、 float...) ,是否都有一个共同的接口? ? ?

如果没有,创建这样一个类的最佳方法是什么?

更新:

我试图实现的主要目标是检查 T 类型的两个变量之间谁更大。

99319 次浏览

恐怕您最接近的是 struct。您将不得不对代码中的数字类型进行更广泛的检查。

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

我不相信您可以使用泛型类型约束来定义它。您的代码可以在内部检查您的需求,可以使用 Double。解析还是双重解析。尝试解析以确定它是否是一个数字—— 或者如果 VB.NET 不是不可能的,那么您可以使用 IsNumeric ()函数。

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

您不能这样做,因为您必须使用单个接口进行算术运算。已经有很多请求在 Connect 上为这个特定的目的添加 IArithμ 接口,但是到目前为止它们都被拒绝了。

您可以通过定义一个没有成员的结构来解决这个问题,该结构实现了一个“ Calculator”接口。我们在 冥王星工具包中的一个插值泛型类中采用了这种方法。对于一个详细的示例,我们有一个“向量”计算器实现 给你,它允许我们的通用插值器使用向量。浮点数、双精度数、四元数等也有类似的。

在 FrameworkBCL (基类库)中,有许多数值函数(如 System 中的函数)。Math)通过为每种数值类型设置重载来处理这个问题。

BCL 中的静态 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);

在数字类型上有一些操作的接口,比如 IComparable<T>IConvertibleIEquatable<T>接口。您可以指定它来获得特定的功能:

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


}

可以使用委托展开具有特定类型操作的类:

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

还可以将委托存储在类中,并使用不同的工厂方法为特定数据类型设置委托。这样,特定于类型的代码只存在于工厂方法中。

什么版本的。你在使用 NET 吗?如果你正在使用。NET 3.5,然后我有一个 通用运算符实现MiscUtil(免费等)。

这里有类似于 T Add<T>(T x, T y)的方法,以及针对不同类型(如 DateTime + TimeSpan)的算术的其他变体。

此外,这适用于所有内置、提升和定制操作符,并缓存委托以获得性能。

为什么这是棘手的一些额外的背景是 给你

您可能还想知道 dynamic(4.0)也间接地解决了这个问题。

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
}

不能仅在编译时执行。 但是你可以加入更多的约束来剔除数字类型中的大多数“坏类型”,如下所示

class yourclass <T>where T: IComparable, IFormattable, IConvertible, IComparabe<T>, IEquatable<T>, struct {...

最后,您仍然必须在运行时使用 object.GetType ()方法检查您的类型是否可以接受。

如果仅仅进行比较,那么只有 ICompatiable < T > 才能解决这个问题。

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


}
}
}