Nullable generic type used with IComparable. Is it possible?
I'm trying to create a simple Clamp (so that I can bound the values of anything com开发者_高级运维parable ... mostly for number types such as int, double, etc.)
The problem is if I do the following I get an error, but according to MSDN IComparable's CompareTo is supposed to be able to handle null values.
Quote: "By definition, any object compares greater than null, and two null references compare equal to each other."public static T Clamp<T>(this T value, T min, T max)
where T : IComparable<T>
{
if (value.CompareTo(max) > 0)
return max;
if (value.CompareTo(min) < 0)
return min;
return value;
}
private Int32? _zip;
public Int32? Zip
{
get
{
return _zip;
}
set
{
_zip = value.Clamp<Int32?>(0, 99999);
}
}
As said by @LBushkin Nullable< T > or T? does not implement IComparable interface. The given solution is ok, however I prefer to have the nullable comparing logic inside a specialized class in that matter, following the Single Responsibility Principle, and also than can be used for comparing any Nullable types.
For example, you could create a generic Nullable type comparer class like this:
public class NullableComparer<T> : IComparer<Nullable<T>>
where T : struct, IComparable<T>
{
public int Compare(Nullable<T> x, Nullable<T> y)
{
//Compare nulls acording MSDN specification
//Two nulls are equal
if (!x.HasValue && !y.HasValue)
return 0;
//Any object is greater than null
if (x.HasValue && !y.HasValue)
return 1;
if (y.HasValue && !x.HasValue)
return -1;
//Otherwise compare the two values
return x.Value.CompareTo(y.Value);
}
}
In this case you would use this class like this:
public static T? Clamp<T>(this T? value, T? min, T? max)
where T : struct
{
var comparer = new NullableComparer<T>();
if (comparer.Compare(value, max) > 0)
return max;
if (comparer.Compare(value, min) < 0)
return min;
return value;
}
Handy for saving in your helpers library.
Hope it helps!
Remember, Int32?
is a shorthand for Nullable<Int32>
. Since Nullable<T>
does not implement IComparable<T>
, your code, as structured, won't compile.
You can, however, overload the method:
public static T? Clamp<T>(this T? value, T? min, T? max)
where T : struct, IComparable<T>
{
// your logic...
}
Of course, if you're planning on working with nullable types, you have to define how you will clamp null
values...
If you don't actually need to clamp null
values, it may be simpler to just first check for null in your property getter:
public Int32? Zip
{
...
set
{
_zip = value == null ? value : value.Value.Clamp<Int32>(0,99999);
}
Or better yet, make it part of the implementation of the additional overload to Clamp
...
精彩评论