有人能告诉我是否有一种方法可以用泛型将泛型类型参数T限制为:
Int16 Int32 Int64 UInt16 UInt32 UInt64
我知道哪里关键字,但不能找到只有这些类型的接口,
喜欢的东西:
static bool IntegerFunction<T>(T value) where T : INumeric
有人能告诉我是否有一种方法可以用泛型将泛型类型参数T限制为:
Int16 Int32 Int64 UInt16 UInt32 UInt64
我知道哪里关键字,但不能找到只有这些类型的接口,
喜欢的东西:
static bool IntegerFunction<T>(T value) where T : INumeric
当前回答
这是没有限制的。对于任何想要使用泛型进行数值计算的人来说,这都是一个真正的问题。
更进一步说,我们需要
static bool GenericFunction<T>(T value)
where T : operators( +, -, /, * )
甚至
static bool GenericFunction<T>(T value)
where T : Add, Subtract
不幸的是,你只有接口,基类和关键字struct(必须是值类型),class(必须是引用类型)和new()(必须有默认构造函数)
你可以把数字包装在其他东西(类似于INullable<T>),就像这里的codeproject。
您可以在运行时应用该限制(通过对操作符进行反射或检查类型),但这首先就失去了使用泛型的优势。
其他回答
我创建了一个小库功能来解决这些问题:
而不是:
public T DifficultCalculation<T>(T a, T b)
{
T result = a * b + a; // <== WILL NOT COMPILE!
return result;
}
Console.WriteLine(DifficultCalculation(2, 3)); // Should result in 8.
你可以这样写:
public T DifficultCalculation<T>(Number<T> a, Number<T> b)
{
Number<T> result = a * b + a;
return (T)result;
}
Console.WriteLine(DifficultCalculation(2, 3)); // Results in 8.
你可以在这里找到源代码:https://codereview.stackexchange.com/questions/26022/improvement-requested-for-generic-calculator-and-generic-number
这个练习的意义是什么?
正如人们已经指出的,你可以让一个非泛型函数取最大的项,编译器会自动为你转换较小的整型。
static bool IntegerFunction(Int64 value) { }
如果您的函数处于性能关键的路径上(在我看来,这是不太可能的),您可以为所有需要的函数提供重载。
static bool IntegerFunction(Int64 value) { }
...
static bool IntegerFunction(Int16 value) { }
不幸的是,在这种情况下,只能在where子句中指定struct。不能具体指定Int16、Int32等,这看起来确实很奇怪,但我相信,在决定不允许在where子句中使用值类型的基础上,有一些深层的实现原因。
我想唯一的解决方案是执行运行时检查,这不幸地阻止了在编译时拾取问题。大概是这样的:-
static bool IntegerFunction<T>(T value) where T : struct {
if (typeof(T) != typeof(Int16) &&
typeof(T) != typeof(Int32) &&
typeof(T) != typeof(Int64) &&
typeof(T) != typeof(UInt16) &&
typeof(T) != typeof(UInt32) &&
typeof(T) != typeof(UInt64)) {
throw new ArgumentException(
string.Format("Type '{0}' is not valid.", typeof(T).ToString()));
}
// Rest of code...
}
我知道这有点难看,但至少提供了所需的约束条件。
我还将研究此实现可能的性能影响,也许有更快的方法。
这个问题有点像常见问题,所以我在维基上发布了这个(因为我之前发布过类似的问题,但这是一个较老的问题);无论如何……
你用的是什么版本的。net ?如果你使用的是。net 3.5,那么我在MiscUtil中有一个通用操作符实现(免费等)。
它有T Add<T>(T x, T y)等方法,以及不同类型上的其他算术变体(如DateTime + TimeSpan)。
此外,这适用于所有内置、提升和定制操作符,并缓存委托以获得性能。
这里有一些关于为什么这很棘手的额外背景。
你可能还想知道动态(4.0)也间接地解决了这个问题。
dynamic x = ..., y = ...
dynamic result = x + y; // does what you expect
. net数字基元类型不共享任何允许它们用于计算的公共接口。可以定义自己的接口(例如ISignedWholeNumber)来执行这样的操作,定义包含单个Int16、Int32等的结构并实现这些接口,然后有方法接受受ISignedWholeNumber约束的泛型类型,但是必须将数值转换为你的结构类型可能是一个麻烦。
An alternative approach would be to define static class Int64Converter<T> with a static property bool Available {get;}; and static delegates for Int64 GetInt64(T value), T FromInt64(Int64 value), bool TryStoreInt64(Int64 value, ref T dest). The class constructor could use be hard-coded to load delegates for known types, and possibly use Reflection to test whether type T implements methods with the proper names and signatures (in case it's something like a struct which contains an Int64 and represents a number, but has a custom ToString() method). This approach would lose the advantages associated with compile-time type-checking, but would still manage to avoid boxing operations and each type would only have to be "checked" once. After that, operations associated with that type would be replaced with a delegate dispatch.