我正在尝试找到一种方法来创建一个只能处理数字类型的通用类,以进行一些计算。
是否存在适用于所有数字类型(int、double、float等)的常见接口?
如果没有,那么创建这样一个类的最佳方法是什么?
更新:
我想要实现的主要目标是检查两个T类型变量之间的大小关系。
我正在尝试找到一种方法来创建一个只能处理数字类型的通用类,以进行一些计算。
是否存在适用于所有数字类型(int、double、float等)的常见接口?
如果没有,那么创建这样一个类的最佳方法是什么?
更新:
我想要实现的主要目标是检查两个T类型变量之间的大小关系。
你正在使用哪个版本的.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
}
对于某些数字类型的操作,例如IComparable<T>
、IConvertible
和IEquatable<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; });
您还可以在类中存储委托,并拥有不同的工厂方法,为特定的数据类型设置委托。这样,特定类型代码仅存在于工厂方法中。
很抱歉,最接近你所需的是结构体。你需要在代码中进行更广泛的数字类型检查。
public class MyClass<T> where T : struct
(...)
由于您必须使用单个接口进行算术运算,因此您无法这样做。已经有很多在Connect上的请求添加一个名为“IArithmetic”接口以实现这一特定目的,但到目前为止它们都被拒绝了。
您可以通过定义一个没有成员的结构体来绕过这个问题,并实现一个“计算器”接口。我们在Pluto Toolkit的插值泛型类中采用了这种方法。例如,我们有一个“向量”计算器实现这里,它让我们的泛型插值器可以处理向量。还有类似的浮点数、双精度数、四元数等。
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);
}
}
}
}
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);
class yourclass <T>where T: IComparable, IFormattable, IConvertible, IComparabe<T>, IEquatable<T>, struct {...
最后,您仍然需要在运行时使用object.GetType()方法检查您的类型是否可接受。
如果只是进行比较,则仅使用IComparable<T>即可完成。
我不相信你可以使用通用类型约束来定义它。你的代码可以在内部检查你的要求,可能使用Double.Parse或Double.TryParse来确定它是否是一个数字 - 如果VB.NET不是问题,那么你可以使用IsNumeric()函数。
编辑: 你可以添加对Microsoft.VisualBasic.dll的引用,并从C#中调用IsNumeric()函数。