如何将这个简单方法变成通用方法?
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;
}
现在,我必须为 byte
、float
、double
和其他数字类型创建它。
众所周知,为这些类型制作大量类似的方法是非常低效的,所以我想把它做成一个泛型方法。以下是我尝试做的事情:
T coerce<T>(T val, T min=(T)0, T max=(T)10) where T:IComparable
{
// ... same as the above ...
}
我知道代码没有 运行,这就是我提出这个问题的原因。我目前对两个问题感到困惑:
如何比较 T
类型?
Visual Studio 对运算符 <
和 >
发出警告。我尝试使用 where T:IComparable
但它没有解决我的问题。
如何设置通用参数的默认值?
我尝试使用 (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>
作为 min
和 max
值,代码可以写成
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;
}
诀窍是使用 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
我有一个方法如下:
int coerce(int val, int min=0, int max = 10)
{
if (val < min)
return min;
if (val > max)
return max;
return val;
}
现在,我必须为 byte
、float
、double
和其他数字类型创建它。
众所周知,为这些类型制作大量类似的方法是非常低效的,所以我想把它做成一个泛型方法。以下是我尝试做的事情:
T coerce<T>(T val, T min=(T)0, T max=(T)10) where T:IComparable
{
// ... same as the above ...
}
我知道代码没有 运行,这就是我提出这个问题的原因。我目前对两个问题感到困惑:
如何比较
T
类型?Visual Studio 对运算符
<
和>
发出警告。我尝试使用where T:IComparable
但它没有解决我的问题。如何设置通用参数的默认值?
我尝试使用
(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>
作为 min
和 max
值,代码可以写成
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;
}
诀窍是使用 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