C# 泛型 - 其中 T 是一个数字?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1267902/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generics - where T is a number?
提问by CD..
I'm trying to figure a way to create a generic class for number types only, for doing some calculations.
我试图找到一种方法来为数字类型创建一个通用类,以进行一些计算。
Is there a common interface for all number types (int, double, float...) that I'm missing???
我缺少的所有数字类型(整数、双精度、浮点数...)都有一个通用接口吗???
If not, what will be the best way to create such a class?
如果没有,创建这样一个类的最佳方法是什么?
UPDATE:
更新:
The main thing I'm trying to achieve is checking who is the bigger between two variables of type T.
我试图实现的主要目标是检查两个 T 类型变量之间谁更大。
采纳答案by Marc Gravell
What version of .NET are you using? If you are using .NET 3.5, then I have a generic operators implementationin MiscUtil(free etc).
您使用的是什么版本的 .NET?如果您使用的是 .NET 3.5,那么我在MiscUtil(免费等)中有一个通用的运算符实现。
This has methods like T Add<T>(T x, T y)
, and other variants for arithmetic on different types (like DateTime + TimeSpan
).
这有像T Add<T>(T x, T y)
和其他不同类型的算术变体(如DateTime + TimeSpan
)。
Additionally, this works for all the inbuilt, lifted and bespoke operators, and caches the delegate for performance.
此外,这适用于所有内置、提升和定制的运算符,并缓存委托以提高性能。
Some additional background on why this is tricky is here.
关于为什么这很棘手的一些额外背景在这里。
You may also want to know that dynamic
(4.0) sort-of solves this issue indirectly too - i.e.
您可能还想知道dynamic
(4.0) 也间接地解决了这个问题 - 即
dynamic x = ..., y = ...
dynamic result = x + y; // does what you expect
Re the comment about <
/ >
- you don't actually needoperators for this; you just need:
关于<
/的评论>
- 您实际上并不需要运算符;您只需要:
T x = ..., T y = ...
int c = Comparer<T>.Default.Compare(x,y);
if(c < 0) {
// x < y
} else if (c > 0) {
// x > y
}
回答by EventHorizon
Closest you get is struct I'm afraid. You'll have to do more extensive checks for number types in code.
恐怕你得到的最接近的是 struct 。您必须对代码中的数字类型进行更广泛的检查。
public class MyClass<T> where T : struct
(...)
回答by STW
I don't believe you can define that using a generic type constraint. Your code could internally check your requirements, possibly using Double.Parse or Double.TryParse to determine if it is a number--or if VB.NET isn't out of the question then you could use the IsNumeric() function.
我不相信您可以使用泛型类型约束来定义它。您的代码可以在内部检查您的要求,可能使用 Double.Parse 或 Double.TryParse 来确定它是否是一个数字——或者如果 VB.NET 没有问题,那么您可以使用 IsNumeric() 函数。
Edit:You can add a reference to Microsoft.VisualBasic.dll and call the IsNumeric() function from c#
编辑:您可以添加对 Microsoft.VisualBasic.dll 的引用并从 c# 调用 IsNumeric() 函数
回答by Reed Copsey
You cannot do this, since you'd have to use a single interface for arithmetic operations. There have been many requests on Connect to add an IArithmetic interface for this specific purpose, but so far they've all been rejected.
您不能这样做,因为您必须使用单个接口进行算术运算。在 Connect 上有很多请求为此特定目的添加 IArithmetic 接口,但到目前为止它们都被拒绝了。
You can sort of work around this by defining a struct with no members, which implements a "Calculator" interface. We took this approach in an interpolation generic class in the Pluto Toolkit. For a detailed example, we have a "vector" calculator implementation here, which lets our generic interpolator work with vectors. There are similar ones for floats, doubles, quaternions, etc.
您可以通过定义一个没有成员的结构来解决这个问题,该结构实现了“计算器”接口。我们在Pluto Toolkit的插值通用类中采用了这种方法。对于一个详细的例子,我们在这里有一个“向量”计算器实现,它让我们的通用插值器可以处理向量。浮点数,双精度数,四元数等也有类似的。
回答by Robert Harvey
In the Framework BCL (base class library), many numeric functions (such as the functions in System.Math) deal with this by having overloads for each numeric type.
在 Framework BCL(基类库)中,许多数字函数(例如 System.Math 中的函数)通过为每个数字类型进行重载来处理这个问题。
The static Math class in the BCL contains static methods, which you can call without having to create an instance of the class. You could do the same in your class. For example, Math.Max has 11 overloads:
BCL 中的静态 Math 类包含静态方法,您无需创建该类的实例即可调用这些方法。你可以在你的课堂上做同样的事情。例如,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);
回答by Guffa
There are interfaces for some of the operations on the number types, like the IComparable<T>
, IConvertible
and IEquatable<T>
interfaces. You can specify that to get a specific functionality:
对数字类型的一些操作有接口,如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;
}
}
You can use delegates to expand a class with type specific operations:
您可以使用委托来扩展具有特定类型操作的类:
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;
}
}
Usage:
用法:
Adder<int> adder = new Adder<int>();
int[] list = { 1, 2, 3 };
int sum = adder.AddAll(list, delegate(int x, int y) { return x + y; });
You can also store delegates in the class, and have different factory methods that sets up delegates for a specific data type. That way the type specific code is only in the factory methods.
您还可以在类中存储委托,并使用不同的工厂方法为特定数据类型设置委托。这样类型特定的代码只在工厂方法中。
回答by dmihailescu
You can not do it at compile time only. But you could put more constraints to weed out most of 'bad types' on your numeric type like below
您不能仅在编译时执行此操作。但是你可以设置更多的限制来清除你的数字类型上的大多数“坏类型”,如下所示
class yourclass <T>where T: IComparable, IFormattable, IConvertible, IComparabe<T>, IEquatable<T>, struct {... In the end you would still have to check at runtime if your type is acceptable using object.GetType() method.
class yourclass <T> where T: IComparable, IFormattable, IConvertible, IComparabe<T>, IEquatable<T>, struct {... 最后,您仍然需要在运行时检查您的类型是否可以使用 object.GetType( ) 方法。
If only comparing, then IComparable<T> alone does the trick.
如果只是比较,那么 IComparable<T> 就可以解决问题。
回答by Tanmay Desai
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 : Division : Multiplication");
int ch = Convert.ToInt32(Console.ReadLine());
if (sel == 1)
{
cs.GetMethodInt<int>(ch);
}
else
{
cs.GetMethodInt<float>(ch);
}
}
}
}