看到他我一下子就悟了-- 泛型(2)

   先说些题外话,只所以写这些东西。是看了CSDN上的曹版主的一篇:手把手教编程,不知道有没有人愿意参与。说实话,我工作四年,总感觉晕晕乎乎的,好多技术都

懂,但是没有一项是精通的。看了这篇帖子,说实在话我可想去,去聆听大神的教导。主要是想提高自己,由于没有时间,又因为身在北京。所以就没有报名(呵呵,报名也

可能没有机会去)。所以自己就去图书馆去搞他提出的这些概念。其实我更希望在北京的大神们也能组织类似的活动。我想响应一定也很多,其实我想如果能组织一次这样的

活动,大神们也会得到提高的。这些都是我在图书馆看书的所得,分享给大家,同时也请管理员同志手下留情,不要每一篇都给打入冷宫,我已经很用心去做了。另外对这

感兴趣的童鞋们可以加我的QQ348537081,我们可以讨论一下心得。最后喜欢看书的童鞋也可以联系我,每周六首都图书馆,风雨无阻。

  说的有些多,下面转入正题。其实这篇文章是泛型介绍(接上一篇,具体的事例随后呈上)的扩展与修改。

因为家中无法联网,我都是提前用wps提前写好的,所有格式上可能会有一些问题,所以请大家多担待。

2.2接口约束(where T:interface-name)

  为了规定某个数据类型必须实现某个接口,需要声明一个接口约束(interface constraint).有了这种约束之后,甚至不需要执行类型转换,就可以调用一个显示的接口成员实现.接

口约束的主要功能与基类约束完全一样。首先,它允许开发人员在泛型类中使用接口的成员。其次,它确保只能使用实现了特定接口的类型实参。这意味着对于任何给定的接

口约束,类型实参要么是接口本身,要么实现了接口的类。

注:可以通过使用逗号分隔的列表来同时指定多个接口。如果某个约束同时包含基类和接口,则先指定基类再指定接口列表。

如:为了确保T类型参数都是先了IComparable接口,

public class Binary<T> where T:System.IComparable{...}

编译器会确保每次使用Binary类的时候,都必须指定一个实现了IComparable接口的类型参数.

 

  下面的程序通过改写前一个程序中的电话列表程序来说明接口约束的用途。在此程序中,PhoneNumber类被转换为一个名为IPhoneNumber的接口。然后,Friend和Supplier实现了该接口。

  

class NotFoundException1 : Exception
    {
        public NotFoundException1() : base() { }

        public NotFoundException1(string str) : base(str) { }

        public NotFoundException1(string str, Exception inner) : base(str, inner) { }

        protected NotFoundException1(System.Runtime.Serialization.SerializationInfo si,
            System.Runtime.Serialization.StreamingContext sc)
            : base(si, sc) { }
    }

    public interface IPhoneNumber
    {
        public string Number { get; set; }

        public string Name { get; set; }
    }

    public class Friend1 : IPhoneNumber
    {
        public string Number { get; set; }

        public string Name { get; set; }

        public bool IsWorkNumber { get; set; }

        public Friend1(string name, string num, bool wk)
        {
            Name = name;
            Number = num;
            IsWorkNumber = wk;
        }
    }

    public class Supplier1 : IPhoneNumber
    {
        public string Name { get; set; }

        public string Number { get; set; }

        public Supplier1(string name, string num)
        {
            this.Name = name;
            this.Number = num;
        }
    }

    class FriendEmail1 { }

    class PhoneList1<T> where T : IPhoneNumber
    {
        T[] phList;
        int end;

        public PhoneList1()
        {
            phList = new T[10];

            end = 0;
        }

        public bool Add(T newEntry)
        {
            if (end == 10) return false;

            phList[end] = newEntry;
            end++;

            return true;
        }

        public T FindByName(string name)
        {
            foreach (T item in phList)
            {
                if (item.Name == name)
                    return item;
            }

            throw new NotFoundException1();
        }

        public T FindByNum(string num)
        {
            foreach (T item in phList)
            {
                if (item.Number == num)
                    return item;
            }

            throw new NotFoundException1();
        }

 

 

 

2.3 struct/class 约束(where T:class/struct)

    另一个重要的泛型约束是将类型参数限制为一个值类型或者一个引用类型.编译器不允许在一个约束中将System.ValueType指定成基类.相反,C#提供了特殊的语法,这种语法同时适用于引用类型.在这种语法中,不是为T指定一个基类.相反,只需要指定关键字struct或者class.在同时存在其他约束时,class或者struct必须位于约束列表的开头

例:

Public struct Nullable<T>:IFormattable,IComparable,IComparable<Nullable<T>>,INullable where T:struct

{//.......}

2.4 new()构造函数约束

  New()构造函数约束允许开发人员实例化一个泛型类型的对象。一般情况下,无法创建一个泛型类型参数的实例。然而,new()约束改变了这种情况,它要求类型实参必须

提供一个无参数的构造函数。在使用new()约束的时候,可以通过调用该无参构造函数来创建对象。

class myclass

        {

            public myclass() { }

        }

        class Test<T> where T : new() 

        {

            T obj;

            public Test() 

            {

                obj = new T();

            }

        }

 

调用:

 Test<myclass> x = new Test<myclass>();

注意:myclass 不必显示地声明一个无参数构造函数,默认的构造函数也可以满足这种约束。然而,如果某个类除了无参的构造函数外还需要定义其他的构造函数,那么必须

为该类显式地声明不含参数的构造函数。

使用new()时,应注意三点:

一、它可以和其他约束一起使用,但必须位于约束列表的末端。

二、New()不允许给类型参数的构造函数传递实参

三、不可以同时使用new()约束和值类型约束

 

2.5多重约束

  同一个参数可以使用多个约束。这种情况下,需要使用一个逗号分隔的约束列表.在该列表中,第一个约束必须是class或者struct(如果存在的话),或者基类(如果被指

定)。指定class或者struct的同时也指定基类约束是非法的。接下来是接口约束。最后是new ()约束。如:

Class Gen<T> where T:myClass,IMyInterface,new(){}

如果有多个类型参数,那么每个类型名称的前面都要使用一个where关键字.如:

Class Gen<T,V> where T:class

Where T:struct

{//.....}

2.6.泛型方法

为了定义泛型方法,需要紧接在方法名之后添加类型参数语法,如

public T method<T>(T params)
{
return params;
}
泛型方法也允许指定约束:

public T method<T>(T params)
where T:IComparable
{
return params;
}

2.7.Default关键字:

  要确定用于创建泛型类实例的类型,需要了解一个最基本的情况:他们是引用类型还是值类型.若不知道这个情况,就不能用下面的代码赋予null值:

public class myGenericClass<T1,T2,T3>
{
    T1 t1;
    public myGenericClass()
{
    t1=null;
}
}

如果T1是值类型,则t1不能是null,所以这段代码将不会编译.幸好,我们可以用default关键字的新用法解决了它.
public myGenericClass()
{
  t1=default(T1);
}

其结果是:如果t1是引用类型,就给它赋予null,如果它是值类型,就赋予默认值.如数字类型,这个默认值就是0.

几个泛型类型的示例:

2.8定义泛型结构

public struct myStruct<T1,T2>
{
  public T1 item1;
  public T2 item2;

}

2.9定义泛型接口
  interface myInterfacee<T>{}

2.10 .定义泛型方法

 public T GetDefault<T>()
{

  return default(T);

}

2.11定义泛型委托

  public delegate T1 myDelegate<T1,T2>(T2 op1,T2 op2) where T1:T2

 

  结束语:泛型到这了,下一次介绍下反射,关于前几篇C#我会抽时间重新写的,能让他更详细点,其实这次C#基础知识的复习让我学到很多东西,以前模糊的概念,

现在变得非常清晰了。我曾经面试过好多人,有工作三年,有两年,甚至工作经验比我还长的。对这些基础性的知识都知之甚少,当然也包括我自己。因为如果没

有这些概念,工作中也不会可虑到这些东西,当然也就谈不上引用。所以我们都只能做底层程序。程序猿想提高,重新学这些基础知识吧,真的……

 

时间: 2024-11-13 06:51:30

看到他我一下子就悟了-- 泛型(2)的相关文章

看到他我一下子就悟了-- 泛型(1)

1.泛型概念:       本质上,术语"泛型"指的是"参数化类型(parameterized types)".参数化类型非常重要,因为它们可以在创建类.结构.方法和委托的时候将要操作的数据类型作为参 数进行指定.使用参数化类型的类.结构.方法和委托都可以称为泛型,如"泛型类"或者"泛型方法".        在具体声明一个变量或者实例化之前,类型参数T只是一个占位符.等到具体声明和实例化的时候,编译器要求代码指定类型参数.泛

看到他我一下子就悟了---委托

看到大家的留言,我想说下我对委托的了解,首先看它的定义: 委托 就是将方法作为方法的参数 不用先看例子什么的,你就多品味品味这句话,然后你看下使用委托的步骤, 1.定义一个委托 2.注册该委托 3.使用委托 Ok就这么简单,其实委托就像大家常说的那样: 它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每次见到委托和事件就觉得心里憋得慌,浑身不自在 其实不用怕,你就按着这三步来标准没错,下面来个小例子: 第一步:定义委托 public delegate void Greetin

C#基础知识回顾--委托事件

在上一篇看到他我一下子就悟了(续)---委托,被人狂喷.说写的太空,没有什么内容之类的.所以准备在这里重写下,不过还是按着以前的方式尽量简单的写.这里我们以打篮球为例. 第一步:首先,其他对象订购事件        当发球的球员产生它的发球事件之前,其他球员需要订购这个事件,采用这种方式,只要出现一个发球事件,其他球 员就能够知道.   第二步:触发事件        当球被发出时,此时发球员对象产生一个新事件.   第三步:球产生一个事件          创建一个新事件,这个事件还有一些参数

参悟JavaScript

引子     编程世界里只存在两种基本元素,一个是数据,一个是代码.编程世界就是在数据和代码千丝万缕的纠缠中呈现出无限的生机和活力.     数据天生就是文静的,总想保持自己固有的本色:而代码却天生活泼,总想改变这个世界.    你看,数据代码间的关系与物质能量间的关系有着惊人的相似.数据也是有惯性的,如果没有代码来施加外力,她总保持自己原来的状态.而代码就象能量,他存在的唯一目的,就是要努力改变数据原来的状态.在代码改变数据的同时,也会因为数据的抗拒而反过来影响或改变代码原有的趋势.甚至在某些

李战:悟透JavaScript

多年前,曾经看过李战大师的"悟透delphi-delphi的原子世界",一直对大师特有的文笔风格记忆犹新,今天无意又看到了大师的"李战:悟透JavaScript",转贴于此,与众分享!   引子    编程世界里只存在两种基本元素,一个是数据,一个是代码.编程世界就是在数据和代码千丝万缕的纠缠中呈现出无限的生机和活力.     数据天生就是文静的,总想保持自己固有的本色:而代码却天生活泼,总想改变这个世界.    你看,数据代码间的关系与物质能量间的关系有着惊人的相

悟透JavaScript整理版第1/2页_javascript技巧

数据天生就是文静的,总想保持自己固有的本色:而代码却天生活泼,总想改变这个世界.    你看,数据代码间的关系与物质能量间的关系有着惊人的相似.数据也是有惯性的,如果没有代码来施加外力,她总保持自己原来的状态.而代码就象能量,他存在的唯一目的,就是要努力改变数据原来的状态.在代码改变数据的同时,也会因为数据的抗拒而反过来影响或改变代码原有的趋势.甚至在某些情况下,数据可以转变为代码,而代码却又有可能被转变为数据,或许还存在一个类似E=MC2形式的数码转换方程呢.然而,就是在数据和代码间这种即矛盾

悟透JavaScript出版啦

前天李战老师发消息来说我们合作的<悟透JavaScript>终于出版了 下午兴冲冲拿到样书,第一次看着自己的涂鸦变成印刷品,自然是十分激动 没错,就是涂鸦! 当然,这其实是一本讲JavaScript的好书 至于为什么会有这么神奇的一本程序书籍,却有一段小故事 当时出版社决定打破技术书籍沉闷的惯例 让这本书读起来更加有趣一点 可惜找了好几个插画er都不尽如人意 程序员和艺术家也许很难沟通 结果刚好碰上我这个懂一点编程又懂一点漫画的打杂小妹 于是李老师决定慷慨的给我这个机会为本书配置插图 从此后的

从《甄嬛传》中悟出的SEO心得体会

最近时间,<甄嬛传>很火,有网友甚至感叹迷倒主妇级观众,求放过我妈.今天不是说<甄嬛传>剧情,而是通过这部电视剧中能够悟出一些SEO道理.有的人就说,你又开始胡扯了,一部电视剧怎么还和我们优化这个行业有联系呢.其实我们做SEO的人不就是要一个发散思维么,哪里有热点,哪里就有我们的存在.世间万物都有有关联,只是要看我们从哪个角度出发,当我们发现了,就会给人眼前一亮之惊喜. 先来说说<甄嬛传>看完后的一点感悟,之后这个SEO心得体会.后宫佳丽三千,要想永远得到皇上的宠爱,就

刘金鸽:做菜过程中悟出的SEO学问

在我们生活中,只要你留心都会有学问.要不然古人怎么会总结出一句话"处处留心皆学问".其实,我在做菜的过程中就误出了一个道理,做SEO就像做菜一样,虽说材料不同,但是他们的原理都是相同的.而对优化这个词我有一个新的解释,优化就是用质优的网站来化解人们心中的疑问.接下来我就给大家具体讲一下我悟出来看学问. 在大家做SEO的过程中,都会有这样的感觉:就是SEO说来说去就是那些东西,没有什么新意.而创新这个东西是靠我们大家来想出来的,我们可以旧瓶装新酒,这样就会有别样的感觉,当大家看我的到标题