与IComparable一起使用的Nullable泛型类型。可能吗?

时间:2010-07-20 21:37:15

标签: c# generics nullable icomparable

我正在尝试创建一个简单的Clamp(这样我就可以绑定任何类似的值...主要用于数字类型,如int,double等)。

问题是,如果我执行以下操作,则会收到错误,但according to MSDN IComparable的CompareTo应该能够处理空值。
Quote:“根据定义,任何对象比较大于null,并且两个空引用比较相等。”

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);
    }
}

2 个答案:

答案 0 :(得分:13)

如@LBushkin Nullable所说&lt; T>还是T?没有实现IComparable接口。给定的解决方案是可以的,但是我更喜欢在Single Responsibility Principle之后在专门的类中使用可空的比较逻辑,并且还可以用于比较任何Nullable类型。

例如,您可以创建一个通用的Nullable类型比较器类,如下所示:

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);
     }

}

在这种情况下,您可以像这样使用此类:

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;
}

方便您在助手库中保存。

希望它有所帮助!

答案 1 :(得分:7)

请记住,Int32?Nullable<Int32>的简写。由于Nullable<T>未实现IComparable<T>,因此您的代码将无法编译。

但是,您可以重载该方法:

public static T? Clamp<T>(this T? value, T? min, T? max) 
    where T : struct, IComparable<T> 
{ 
    // your logic...
} 

当然,如果您计划使用可空类型,则必须定义如何限制null值......

如果您实际上不需要钳制null值,那么首先在属性getter中检查null可能更简单:

public Int32? Zip
{
   ...
   set
   {
       _zip = value == null ? value : value.Value.Clamp<Int32>(0,99999);
   }

或者更好的是,将其作为Clamp ...

的额外重载实现的一部分