有人能告诉我是否有一种方法可以用泛型将泛型类型参数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
当前回答
我创建了一个小库功能来解决这些问题:
而不是:
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
其他回答
话题老了,但对未来的读者来说:
这个特性与歧视联盟紧密相关,而歧视联盟目前还没有在c#中实现。我发现它的问题在这里:
https://github.com/dotnet/csharplang/issues/113
这个问题仍然没有解决,并且已经计划在c# 10中推出新特性
所以我们仍然需要等待一段时间,但在释放之后,你可以这样做:
static bool IntegerFunction<T>(T value) where T : Int16 | Int32 | Int64 | ...
我有一个类似的情况,我需要处理数字类型和字符串;看起来有点奇怪,但就是这样。
和许多人一样,我研究了约束条件,提出了一堆它必须支持的接口。然而,第一,它并不是100%无懈可击的;第二,任何新看到这一长串约束条件的人都会立刻感到困惑。
所以,我的方法是把我所有的逻辑放到一个没有约束的泛型方法中,但是让这个泛型方法是私有的。然后我用公共方法公开它,其中一个方法显式地处理我想处理的类型——在我看来,代码是干净而显式的,例如。
public static string DoSomething(this int input, ...) => DoSomethingHelper(input, ...);
public static string DoSomething(this decimal input, ...) => DoSomethingHelper(input, ...);
public static string DoSomething(this double input, ...) => DoSomethingHelper(input, ...);
public static string DoSomething(this string input, ...) => DoSomethingHelper(input, ...);
private static string DoSomethingHelper<T>(this T input, ....)
{
// complex logic
}
这是没有限制的。对于任何想要使用泛型进行数值计算的人来说,这都是一个真正的问题。
更进一步说,我们需要
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。
您可以在运行时应用该限制(通过对操作符进行反射或检查类型),但这首先就失去了使用泛型的优势。
使用策略的解决方案:
interface INumericPolicy<T>
{
T Zero();
T Add(T a, T b);
// add more functions here, such as multiplication etc.
}
struct NumericPolicies:
INumericPolicy<int>,
INumericPolicy<long>
// add more INumericPolicy<> for different numeric types.
{
int INumericPolicy<int>.Zero() { return 0; }
long INumericPolicy<long>.Zero() { return 0; }
int INumericPolicy<int>.Add(int a, int b) { return a + b; }
long INumericPolicy<long>.Add(long a, long b) { return a + b; }
// implement all functions from INumericPolicy<> interfaces.
public static NumericPolicies Instance = new NumericPolicies();
}
算法:
static class Algorithms
{
public static T Sum<P, T>(this P p, params T[] a)
where P: INumericPolicy<T>
{
var r = p.Zero();
foreach(var i in a)
{
r = p.Add(r, i);
}
return r;
}
}
用法:
int i = NumericPolicies.Instance.Sum(1, 2, 3, 4, 5);
long l = NumericPolicies.Instance.Sum(1L, 2, 3, 4, 5);
NumericPolicies.Instance.Sum("www", "") // compile-time error.
该解决方案是编译时安全的。CityLizard框架提供了。net 4.0的编译版本。文件名为“lib/NETFramework4.0/ citylizad . policy .dll”。
它也可以在Nuget: https://www.nuget.org/packages/CityLizard/。参见CityLizard.Policy.I结构。
我想知道和samjudson一样,为什么只对整数有效?如果是这样的话,你可能想要创建一个helper类或者类似的东西来保存你想要的所有类型。
如果你想要的只是整数,不要使用泛型,那不是泛型;或者更好的是,通过检查其类型来拒绝任何其他类型。