如何将这个简单方法变成通用方法?

How can I make this simple method into a generic method?

我有一个方法如下:

int coerce(int val, int min=0, int max = 10)
{
    if (val < min)
        return min;
    if (val > max)
        return max;
    return val;
}

现在,我必须为 bytefloatdouble 和其他数字类型创建它。

众所周知,为这些类型制作大量类似的方法是非常低效的,所以我想把它做成一个泛型方法。以下是我尝试做的事情:

T coerce<T>(T val, T min=(T)0, T max=(T)10) where T:IComparable
{
    // ... same as the above ...
}

我知道代码没有 运行,这就是我提出这个问题的原因。我目前对两个问题感到困惑:

  1. 如何比较 T 类型?

    Visual Studio 对运算符 <> 发出警告。我尝试使用 where T:IComparable 但它没有解决我的问题。

  2. 如何设置通用参数的默认值?

    我尝试使用 (T)0(T)10。但无论如何,这不是一个好的选择。

这可能是一个简单的问题,但我找不到 Google 的答案。

您应该使用 Compare 方法而不是 <> 运算符。并应用正确的通用约束,对于数字类型,它应该是 IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable。但是,您可以只保留 where T : struct, IComparable<T>,它应该足以满足您的目的(但是 struct 在这里很重要,因为您正在比较值类型)

T coerce<T>(T val, T min, T max) where T : struct, IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
{
    if (val.CompareTo(min) < 0)
        return min;
    if (val.CompareTo(max) > 0)
        return max;

    return val;
}

您还可以指定默认 min 值,例如 T min = default(T),但您不能为 max 值指定默认值。

根据评论,如果使用 Nullable<T> 作为 minmax 值,代码可以写成

T coerce<T>(T val, T? min = default, T? max = default) where T : struct, IComparable<T>
{
    var minValue = min.HasValue ? min.Value : default(T);
    var maxValue = max.HasValue ? max.Value : (T)Convert.ChangeType(10, typeof(T));

    if (val.CompareTo(minValue) < 0)
        return minValue;
    if (val.CompareTo(minValue) > 0)
        return maxValue;

    return val;
}
public T Max<T>(T val, T min, T max) where T : IComparable<T>
{
    if (val.CompareTo(min) == -1)
        return min;

    if (val.CompareTo(min) == 1)
        return max;

    return val;
}

Detail

诀窍是使用 IComparable 方法,而不是比较运算符。在这种情况下,CompareTo 方法

参数的默认值并不容易,您假设数值并进行直接转换,但 T 可以是任何 IComparable 数据类型

public static T Coerce<T>(T val, T min, T max) where T:IComparable {
    if (val.CompareTo(min) < 0)
        return min;
    else if (val.CompareTo(max) > 0)
        return max;
    else
        return val;
}

Fiddle: https://dotnetfiddle.net/fJUDdR