I have a method as follows:
int coerce(int val, int min=0, int max = 10)
{
if (val < min)
return min;
if (val > max)
return max;
return val;
}
Now, I have to make it for byte
, float
, double
, and other numeric types.
As all we know, making numerous similar methods for those types is very ineffective, so I want to make it into a generic method. The following is the what I tried to do:
T coerce<T>(T val, T min=(T)0, T max=(T)10) where T:IComparable
{
// ... same as the above ...
}
I know that the code does not run, and that's why I'm asking for this. I'm currently confused by two questions:
How can I compare T
types?
Visual Studio warns about the operator <
and >
. I tried to use where T:IComparable
but it did not solve my problem.
How can I set default values for a generic argument?
I tried to use (T)0
and (T)10
for it. But it was not a good choice, anyway.
It may be a simple question, but I couldn't find answer from Google.
You should use Compare
method instead of <
or >
operators. And apply the correct generic constraints, for numeric types it should be IComparable, IComparable<T>, IConvertible, IEquatable<T>, IFormattable
. However, you can leave only where T : struct, IComparable<T>
, it should be enough for your purposes (but struct
is important here, since you are comparing value types)
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;
}
You can also specify the default min
value like T min = default(T)
, but you can't do that for max
value.
Following the comments, in case of using Nullable<T>
for min
and max
values the code can be written like
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;
}