zoukankan      html  css  js  c++  java
  • c# 扩展方法奇思妙用基础篇七:IsBetween 通用扩展

    相信大家在看了本文的题目之后,马上就能写出 IsBetween 扩展来:

    public static bool IntIsBetween(this int i, int lowerBound, int upperBound, 
        bool includeLowerBound = false, bool includeUpperBound = false)
    {
        return (includeLowerBound && i == lowerBound) ||
            (includeUpperBound && i == upperBound) ||
            (i > lowerBound && i < upperBound);
    }

    大家的写法可能不尽相同,但效果都是一样的,以上可能是最精简的写法了吧,类似可以写出其它数据类型 IsBetween 来:

    public static bool IntIsBetween(this long i, long lowerBound, long upperBound,
    bool includeLowerBound = false, bool includeUpperBound = false)
    {
        return (includeLowerBound && i == lowerBound) ||
            (includeUpperBound && i == upperBound) ||
            (i > lowerBound && i < upperBound);
    }
    public static bool DoubleIsBetween(this float i, float lowerBound, float upperBound,
            bool includeLowerBound = false, bool includeUpperBound = false)
    {
        return (includeLowerBound && i == lowerBound) ||
            (includeUpperBound && i == upperBound) ||
            (i > lowerBound && i < upperBound);
    }

    不过这样写下去可是很罗嗦的,.net 中的数值类型太多了,除了上面几个还有:short、long、ushort、uint、ulong、double、decimal…

    此外,我们还有其它要类型如:string、DateTime 等也要进行 IsBetween 判断,一个一个写来不优雅。

    泛型版本 IsBetween 扩展

    .Net 中 IComparable<T> 接口 定义了值类型或类的通用比较方法,借助于此接口,写一个通用的 IsBetween 就容易多了:

    public static bool IsBetween<T>(this T t, T lowerBound, T upperBound,
        bool includeLowerBound = false, bool includeUpperBound = false)
            where T: IComparable<T>
    {
        if(t == null) throw new ArgumentNullException("t");
    
        var lowerCompareResult = t.CompareTo(lowerBound);
        var upperCompareResult = t.CompareTo(upperBound);
    
        return (includeLowerBound && lowerCompareResult == 0) ||
            (includeUpperBound && upperCompareResult == 0) ||
            (lowerCompareResult > 0 && upperCompareResult < 0);
    }

    这个是相当通用的,支持 .net 中的所有数值类型,也支持 string、DateTime,因为它们都实现了 IComparable<T> 接口,下面是一些调用代码:

    //int
    bool b0 = 3.IsBetween(1, 5);
    bool b1 = 3.IsBetween(1, 3, includeUpperBound: true);
    bool b2 = 3.IsBetween(3, 5, includeLowerBound: true);
    //double
    bool b3 = 3.14.IsBetween(3.0, 4.0);
    //string
    bool b4 = "ND".IsBetween("NA", "NC");
    //DateTime
    bool b5 = new DateTime(2011, 2, 17).IsBetween(new DateTime(2011, 1, 1), new DateTime(2011, 3, 1));

    带 IComparer<T> 参数的 IsBetween 扩展

    上面的扩展很通用,但还不够好,比如下面的 Person 类:

    public class Person
    {
        public string Name { get; set; }
        public DateTime Birthday { get; set; }
    }

    没有实现任何 IComparable<T> 接口,但我们需要确定某人是否界于另外两人这间,根据生日或其它条件判断。

    使用 .Net 中另外一个关于通用比较的接口 IComparer<T> 接口,我们再创建一个扩展:

    public static bool IsBetween<T>(this T t, T lowerBound, T upperBound, IComparer<T> comparer, 
        bool includeLowerBound = false, bool includeUpperBound = false)
    {
        if (comparer == null) throw new ArgumentNullException("comparer");
    
        var lowerCompareResult = comparer.Compare(t, lowerBound);
        var upperCompareResult = comparer.Compare(t, upperBound);
    
        return (includeLowerBound && lowerCompareResult == 0) ||
            (includeUpperBound && upperCompareResult == 0) ||
            (lowerCompareResult > 0 && upperCompareResult < 0);
    }

    这个扩展需要一个 IComparer<T> 的实例,我们先来实现人员生日的“比较器” :

    public class PersonBirthdayComparer : IComparer<Person>
    {
        public int Compare(Person x, Person y)
        {
            return Comparer<DateTime>.Default.Compare(x.Birthday, y.Birthday);
        }
    }

    人员生日 IsBetween 示例代码如下:

    var p1= new Person{ Name = "鹤冲天",  Birthday  = new DateTime(1990, 1, 1)};
    var p2= new Person{ Name = "鹤中天",  Birthday  = new DateTime(2000, 1, 1)};
    var p3= new Person{ Name = "鹤微天",  Birthday  = new DateTime(2010, 1, 1)};
    bool b6 = p2.IsBetween(p1, p3, new PersonBirthdayComparer());

    类似,我们还可以对人员进行身高、体重、人品等其它方面的 IsBetween 判断,只需要传入不同的 comparer。

    针对 IComparable<T> 接口的 IsBetween 扩展

    之前一篇文章中,我曾说过要针对接口扩展,我们何不针对 IComparable<T> 接口 进行扩展呢:

    public static bool IsBetween<T>(this IComparable<T> t, T lowerBound, T upperBound,
        bool includeLowerBound = false, bool includeUpperBound = false)
    {
        if (t == null) throw new ArgumentNullException("t");
    
        var lowerCompareResult = t.CompareTo(lowerBound);
        var upperCompareResult = t.CompareTo(upperBound);
    
        return (includeLowerBound && lowerCompareResult == 0) ||
            (includeUpperBound && upperCompareResult == 0) ||
            (lowerCompareResult > 0 && upperCompareResult < 0);
    }

    这个扩展的应用场景可能不多,这里举一个方便大家理解,假定我们自定义了一个大整数类形:

    public class BigInt: IComparable<int>, IComparable<double>
    {
        //...
        public int CompareTo(int other)
        {
            //...
        }
        public int CompareTo(double other)
        {
            //...
        }
    }

    因为它实 IComparable<int> 和 IComparable<double>,所以可以和 int 和 double 进行比较,则可以如下使用:

    BigInt bi = new BigInt();
    bool b8 = bi.IsBetween(10, 20);
    bool b9 = bi.IsBetween(1.424E+12, 2.3675E+36);

    ( .Net 中已经有了大整数类型,请参见:BigInteger 结构,不过没有实现 IComparable<int> 和 IComparable<double> )

    其它比较扩展

    有了上面的 IsBetween 扩展,再写其它比较扩展就易如反掌了,比如下面几个:

    • LessThan
    • LessOrEquals
    • GreatOrEquals
    • GreatThan
  • 相关阅读:
    Ajax
    事件委托
    事件对象
    js的基础类型与引用类型
    Javascript和HTML dom
    用jQuery写的最简单的表单验证
    初学HTML5的一点理解
    CMake 入门
    centos7上rpm安装wkhtmltopdf
    centos7 下安装思源黑体字体
  • 原文地址:https://www.cnblogs.com/ywsoftware/p/3128753.html
Copyright © 2011-2022 走看看