• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    .NET开发基础:从简单的例子理解泛型 分享

    从简单的例子理解泛型
    话说有家影视公司选拔偶像派男主角,导演说了,男演员,身高是王道。于是有下面代码:
     

    复制代码 代码如下:

    //男演员实体类
    public class Boy
    {
        //姓名
        private string mName;
        //身高
        private int mHeight;
        public string Name {
            get { return this.mName; }
        }
        public int Height {
            get { return this.mHeight; }
        }

        public Boy(string name, int height) {
            this.mName = name;
            this.mHeight = height;
        }
    }

     
    //演员选拔类
    public class Compare
    {
        //导演导超女出生,喜欢一对一PK
        public Boy WhoIsBetter(Boy boy1, Boy boy2)
        {
            if (boy1.Height > boy2.Height)
            {
                return boy1;
            }
            else
            {
                return boy2;
            }
        }
    }

     
    //测试
    static void Main(string[] args)
    {
        Boy boy1 = new Boy("潘长江", 165);
        Boy boy2 = new Boy("刘德华", 175);

        Console.WriteLine(new Compare().WhoIsBetter(boy1, boy2).Name);
        Console.ReadLine();
    }
     


    代码很简单,Boy为男演员实体类,包含姓名和身高两个字段属性;Compare类中的WhoIsBetter为选拔逻辑方法,负责选出两个男演员中较高的那个;测试结果:刘德华完胜。

    任何行业都是一样,需求变更无处不在。第二天,需要选女主角,导演说了,女演员,苗条是王道。于是代码变更,添加了女演员实体类,添加了女演员的选拔方法:
     
    复制代码 代码如下:

    //添加女演员实体
    public class Girl
    {
        //姓名
        private string mName;
        //体重
        private int mWeight;
        public string Name
        {
            get { return this.mName; }
        }
        public int Weight
        {
            get { return this.mWeight; }
        }

        public Girl(string name, int weight){
            this.mName = name;
            this.mWeight = weight;
        }
    }

     
    //演员选拔类中添加一个女演员方法
    public class Compare
    {
        //男演员身高是王道
        public Boy WhoIsBetter(Boy boy1, Boy boy2)
        {
            if (boy1.Height > boy2.Height)
            {
                return boy1;
            }
            else
            {
                return boy2;
            }
        }

        //女演员苗条是王道
        public Girl WhoIsBetter(Girl girl1, Girl girl2)
        {
            if (girl1.Weight girl2.Weight)
            {
                return girl1;
            }
            else
            {
                return girl2;
            }
        }
    }

     
    //测试
    static void Main(string[] args)
    {
        Boy boy1 = new Boy("潘长江", 165);
        Boy boy2 = new Boy("刘德华", 175);

        Girl girl1 = new Girl("巩俐", 120);
        Girl girl2 = new Girl("周迅", 80);

        Console.WriteLine(new Compare().WhoIsBetter(boy1, boy2).Name);
        Console.WriteLine(new Compare().WhoIsBetter(girl1, girl2).Name);
        Console.ReadLine();
    }
     


    结果选出了身高更高的刘德华,选出了体重更轻的周迅,导演很满意。但从程序设计角度,这段代码显然不够完美,第一天选男主角,第二天选女主角,往后还要选男配角,选女配角,选群众......按目前方式,只有往Compare类里不断添加方法才能满足导演需求,方法会越来越多,代码会越来越长。于是,我决定修改WhoIsBetter方法,让它以后可以支持男主,女主,男配,女配,男群众,女群众甚至支持所有两个对象之间的比较:
     
    复制代码 代码如下:

    /// summary>
    /// 男演员:实现IComparable接口
    /// /summary>
    public class Boy : IComparable
    {
        //姓名
        private string mName;
        //身高
        private int mHeight;
        public string Name {
            get { return this.mName; }
        }
        public int Height {
            get { return this.mHeight; }
        }

        public Boy(string name, int height) {
            this.mName = name;
            this.mHeight = height;
        }

        public int CompareTo(object obj)
        {
            //比较身高
            return this.mHeight - ((Boy)obj).Height;
        }
    }

    /// summary>
    /// 女演员:实现IComparable接口
    /// /summary>
    public class Girl : IComparable
    {
        //姓名
        private string mName;
        //体重 www.jb51.net
        private int mWeight;
        public string Name
        {
            get { return this.mName; }
        }
        public int Weight
        {
            get { return this.mWeight; }
        }

        public Girl(string name, int weight){
            this.mName = name;
            this.mWeight = weight;
        }

        public int CompareTo(object obj)
        {
            //比较体重
            return ((Girl)obj).Weight - this.mWeight;
        }
    }
     


    首先让实体类支持自定义的比较,男演员比较身高,女演员比较体重。自定义比较是通过实现IComparable接口完成的,在C#里但凡可以比较的类型,比如int、double、char等都实现了IComparable接口。关于IComparable接口此处不作详述,请读者自行查阅相关资料。
     
    复制代码 代码如下:

    public class Compare
    {
        //万物皆object
        public object WhoIsBetter(object obj1, object obj2)
        {
            object result = obj2;
            //判断比较类型必须相同
            if (obj1.GetType() == obj2.GetType())
            {
                switch (obj1.GetType().ToString())
                {
                    //男演员选拔
                    case "Generic.Boy":
                        if (((Boy)obj1).CompareTo(obj2) > 0)
                        {
                            result = obj1;
                        }
                        break;
                    //女演员选拔
                    case "Generic.Girl":
                        if (((Girl)obj1).CompareTo(obj2) > 0)
                        {
                            result = obj1;
                        }
                        break;
                    //扩展int类型比较
                    case "System.Int32":
                        if (((System.Int32)obj1).CompareTo(obj2) > 0)
                        {
                            result = obj1;
                        }
                        break;
                    }
                }
                return result;
            }
        }
     

    修改WhoIsBetter方法,除了支持对男演员、女演员的比较,为了展示其扩展性,还新增了int类型的比较。
     
    复制代码 代码如下:

    //测试
    static void Main(string[] args)
    {
         Boy boy1 = new Boy("潘长江", 165);
         Boy boy2 = new Boy("刘德华", 175);

         Girl girl1 = new Girl("巩俐", 120);
         Girl girl2 = new Girl("周迅", 80);

         Console.WriteLine(((Boy)new Compare().WhoIsBetter(boy1, boy2)).Name);
         Console.WriteLine(((Girl)new Compare().WhoIsBetter(girl1, girl2)).Name);
         Console.WriteLine(new Compare().WhoIsBetter(boy1.Height, boy2.Height));
         Console.WriteLine(new Compare().WhoIsBetter(girl1.Weight, girl2.Weight));

         Console.ReadLine();
    }
     


    测试结果:
    刘德华
    周迅
    175
    120
    OK,截止目前,似乎比较完美了,男演员比身高,女演员比体重,还支持int类型比大小,WhoIsBetter方法具有了重用性,如果有需要,往后还能扩展,拿来比较任意两个对象。在泛型出现以前,似乎确实比较完美,但这也只是相对的,我们来看看目前代码的弱点:
    弱点1:方法的重用性
    假设我们要让WhoIsBetter方法支持更多类型,比如支持基本的double,char,bool类型,支持以后导演可能提出的配角比较,群众比较,那么就必须不断的扩展方法内部代码,这带来极大的维护成本。
    弱点2:类型安全问题
     
    复制代码 代码如下:

    //测试
    static void Main(string[] args)
    {
        Boy boy1 = new Boy("潘长江", 165);
        Boy boy2 = new Boy("刘德华", 175);

        Girl girl1 = new Girl("巩俐", 120);
        Girl girl2 = new Girl("周迅", 80);

        Console.WriteLine(((Boy)new Compare().WhoIsBetter(boy1, girl1)).Name);
        Console.ReadLine();
    }
     


    如上代码我拿潘长江跟巩俐去比较。虽然万能的object给我们带来了便捷,同时也带来了风险,这段代码编译完全可以通过,但运行时会出现异常,girl对象是没法转换为Boy类型的,现实里去韩国可以变性,但代码里绝对不行。所以这个方法就像颗定时炸弹,一不小心传错了参数,就会导致严重后果,并且编译阶段完全不被发现。
    弱点3:装箱拆箱导致的性能问题
    当向WhoIsBetter方法中传递int参数时,object转换为int导致了拆箱操作:
    if (((System.Int32)obj1).CompareTo(obj2) > 0)
    反编译获取MSIL:
    IL_0093:  unbox.any  [mscorlib]System.Int32
    C#是强类型语言,但只要引用类型与值类型的相互转换,就避免不了Box与Unbox。有关装箱与拆箱的知识请读者自行查阅相关资料,此处不作详述。

    理解泛型
    OK,到泛型登场了,摘录了一段MSDN中对泛型的描述:泛型类和泛型方法同时具备可重用性、类型安全和效率,这是非泛型类和非泛型方法无法具备的。这三点,跟我们上面的例子相吻合。
    看看使用泛型的解决方案:
     
    复制代码 代码如下:

    public class CompareT> where T : IComparable
    {
        public T WhoIsBetter(T t1, T t2)
        {
            if (t1.CompareTo(t2) > 0)
            {
                return t1;
            }
            else
            {
                return t2;
            }
        }
    }

     
    //测试
    static void Main(string[] args)
    {
        Boy boy1 = new Boy("潘长江", 165);
        Boy boy2 = new Boy("刘德华", 175);

        Girl girl1 = new Girl("巩俐", 120);
        Girl girl2 = new Girl("周迅", 80);

        Console.WriteLine((new CompareBoy>().WhoIsBetter(boy1, boy2)).Name);
        Console.WriteLine((new CompareGirl>().WhoIsBetter(girl1, girl2)).Name);
        Console.WriteLine(new Compareint>().WhoIsBetter(boy1.Height, boy2.Height));
        Console.WriteLine(new Comparestring>().WhoIsBetter(boy1.Name, girl1.Name));
        Console.ReadLine();
    }
     


    这段代码在优雅度上完胜非泛型,并且可重用性大大提升,可以说它支持所有类型的比较,只要这个类型实现了IComparable接口,同时一劳永逸,不再需要在方法内部作任何扩展。
    public class CompareT> where T : IComparable{
        //...
    }
    泛型类的定义是在类名后面跟上T>,这个是泛型专用语法,T表示传递进来的类型,你也可以用别的字母代替。
    where T : IComparable ,从字面上就能理解,这段表示对T的类型约束。程序是遵循人的意志来执行的,按前面的例子,如果莫名其妙的让程序比较两个object,它没办法知道该去怎么比较。所以我们必须告诉程序,T必须是可比较的类型,T必须实现了IComparable接口。
    关于泛型参数约束,MSDN提供了一张表格:

    约束 说明
    T:结构 类型参数必须是值类型。可以指定除Nullable 以外的任何值类型。
    T:类 类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
    T:new() 类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
    T:基类名> 类型参数必须是指定的基类或派生自指定的基类。
    T:接口名称> 类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
    T:U 为T 提供的类型参数必须是为U 提供的参数或派生自为U 提供的参数。 

    您可能感兴趣的文章:
    • asp.net实现利用反射,泛型,静态方法快速获取表单值到Model的方法
    • 详解.NET 4.0中的泛型协变(covariant)和反变(contravariant)
    • .NET基础之自定义泛型分析
    • .net泛型通用函数的特殊问题的解决方法
    • 使用.NET中的Action及Func泛型委托深入剖析
    • .NET CORE动态调用泛型方法详解
    上一篇:ASP.NET MVC 4 捆绑和缩小实例介绍
    下一篇:Asp.net中把Excel数据存储至SQL Server中的具体实现方法
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    .NET开发基础:从简单的例子理解泛型 分享 .NET,开发,基础,从,简单,