有人能告诉我是否有一种方法可以用泛型将泛型类型参数T限制为:

Int16 Int32 Int64 UInt16 UInt32 UInt64

我知道哪里关键字,但不能找到只有这些类型的接口,

喜欢的东西:

static bool IntegerFunction<T>(T value) where T : INumeric 

当前回答

使用策略的解决方案:

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结构。

其他回答

这个练习的意义是什么?

正如人们已经指出的,你可以让一个非泛型函数取最大的项,编译器会自动为你转换较小的整型。

static bool IntegerFunction(Int64 value) { }

如果您的函数处于性能关键的路径上(在我看来,这是不太可能的),您可以为所有需要的函数提供重载。

static bool IntegerFunction(Int64 value) { }
...
static bool IntegerFunction(Int16 value) { }

没有办法将模板限制为类型,但是可以根据类型定义不同的操作。作为泛型数值包的一部分,我需要一个泛型类来添加两个值。

    class Something<TCell>
    {
        internal static TCell Sum(TCell first, TCell second)
        {
            if (typeof(TCell) == typeof(int))
                return (TCell)((object)(((int)((object)first)) + ((int)((object)second))));

            if (typeof(TCell) == typeof(double))
                return (TCell)((object)(((double)((object)first)) + ((double)((object)second))));

            return second;
        }
    }

请注意,typeofs是在编译时计算的,因此if语句将被编译器删除。编译器还会删除虚假的类型转换。因此,在编译器中会解析为

        internal static int Sum(int first, int second)
        {
            return first + second;
        }

话题老了,但对未来的读者来说:

这个特性与歧视联盟紧密相关,而歧视联盟目前还没有在c#中实现。我发现它的问题在这里:

https://github.com/dotnet/csharplang/issues/113

这个问题仍然没有解决,并且已经计划在c# 10中推出新特性

所以我们仍然需要等待一段时间,但在释放之后,你可以这样做:

static bool IntegerFunction<T>(T value) where T : Int16 | Int32 | Int64 | ...

不幸的是,在这种情况下,只能在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...
}

我知道这有点难看,但至少提供了所需的约束条件。

我还将研究此实现可能的性能影响,也许有更快的方法。

我创建了一个小库功能来解决这些问题:

而不是:

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