step1-泛型2

一泛型优点

      泛型类和泛型方法同时具备可重用性、类型安全和效率,这是非泛型类和非泛型方法无法具备的。以下依次对其进行详细说明。

1.类型安全

非泛型,如当ArrayList添加了一个字符类型时,存在一个字符向对象的隐式转换。同样,如果自列表检索一个字符类型对象时,存在一个自Object向字符类型的显示转换。

而检索类型对象时,是在运行时进行检查,因此,存在不安全性(如eg2非泛型,在运行时,将"e"转换为int时,会抛出类型转换的错误)。

相反,泛型如List<String> 允许程序在编译时而不是运行时对变量类型进行确定及检查(如eg1泛型).

2.效率

(1) 在JIT编译时而不是在执行过程中进行类型检查,性能会得到提高。

(2) 另外,对于值类型而言,使用非泛型需要对值类型进行装箱,拆箱,会浪费很多时间。

eg1泛型:

List<String>  lis=new List<string>();

lis.Add("a");//不进行装箱。

lis.Add(System.DateTime);//在编译时便会报错,而不是在运行时才检查错误。

string a=lis[0];//不需要类型转换。

eg2非泛型:

       public ArrayList AddToArrayList()

        {

            ArrayList arrlist =new ArrayList();

            arrlist.Add(1);//装箱string-->object

            arrlist.Add(2);

            arrlist.Add("e");

            return arrlist;

        }

        public void ReadFromArrayList(ArrayList arr)

        {

            int[] intvalue = new int[3];

            for(int i=0; i<arr.Count; i++)

            {

                intvalue[i] = Convert.ToInt32(arr[i]);

            }

        }

3.可重用性

泛型能够实现对具有相同功能的代码重用。避免了重写代码带来的烦恼。

3.1需求描述

public classDog

{

   public string Name { get; set; }

}

 

public classCat

{

public string Name {get; set; }

}

 

  现在有一个需求,要求将DogCat的名字打印出来,写两个方法,分别用于打印DogCat的名字:

public staticvoid PrintDogName(Dog dog)

{

 Console.WriteLine(dog.Name);

}

public staticvoid PrintCatName(Cat cat)

{

 Console.WriteLine(cat.Name);

}

 

3.2合并方法

public staticvoid PrintName<T>(T t)

{

if (t is Dog)

{

Console.WriteLine((t as Dog).Name);

return;

}

if (t is Cat)

{

Console.WriteLine((t as Cat).Name);

return;

}

}

3.3最终优化

而(2)中方法是把方法合并成一个了,但总的代码量没有减少。只是把原来两个方法里的代码拿到一个方法里来,可以将Dog类和Cat类抽象出一个接口:

interface IName

{

string Name { get; set; }

}

 

 public class Dog : IName

{

public string Name {get; set; }

}

public class Cat:IName

{

public string Name {get; set; }

}

//限制泛型:必须实现Iname接口。

public staticvoid PrintName<T>(T t)where T:IName

{

Console.WriteLine(t.Name);

}

 

二泛型应用

泛型是具有占位符(类型参数)的类、结构、接口和方法,这些占位符可以具有一个或多个类型。

1泛型类

1.1简单泛型类定义

带有泛型参数列表。

public class Generic<T>

{

      public T Field;

}

1.2 如何实例化泛型类

需指定实际类型来替换类型参数。这会建立一个新的泛型类,称为构造泛型类,选定的类型将替换所有出现的类型参数。

Generic<string> g = new Generic<string>();

g.Field = "A string";

2 泛型方法

2.1泛型方法定义

具有两个参数列表的方法:一个泛型类型参数列表和一个形参列表。类型参数可以作为返回类型或形参的类型出现。

2.2泛型方法解析

示例中泛型类型参数列表为<T>,形参列表为(T arg)。形参和返回类型都为泛型类型T。

T Generic<T>(T arg) { T temp = arg; ...}

2.3注意

只有当方法具有它自己的类型参数列表时,才能称其为泛型方法。在下面的代码中,只有方法 G是泛型方法。

class A 

{

      T G<T>(T arg) {...}

}

class Generic<T>

{

 T M(T arg) {...}

}

3 泛型接口

3.1泛型接口定义

      以常用泛型接口为例:System. IComparable<T> System. IEquatable< T>IComparable< T>接口定义 CompareTo 方法,该方法确定实现类型的实例的排序顺序。 IEquatable<T>接口定义Equals 方法,该方法确定实现类型的实例的相等性。示例中泛型类型参数列表为<T>。

   public interfaceIEquatable<T>

    {

        bool Equals(T other);

}

3.2泛型接口使用

public classPerson : IEquatable<Person>

{

      public Person(string lastName,string ssn)

    {

        this.SSN = ssn;

        this.LastName = lastName;

    }

    public string SSN

    {

        get { return this.uniqueSsn; }

        set

        {

            uniqueSsn = value;

        }

    }

 

    public string LastName

    {

        get { return this.lName; }

        set

        {

            lName = value;

        }

    }

 

    public bool Equals(Person other) //继承接口的方法。

    {

        if (this.uniqueSsn == other.SSN)

            return true;

        else

            return false;

    }

 }

public classTestIEquatable

{

    public static void Main()

    {

        // Create a Person object for each job applicant.

        Person applicant1 = new Person("Jone","1");

        Person applicant2 = new Person("Jone","2");

        applicants.Add(applicant1);

        applicants.Add(applicant2);

        // Create a Person object for the final candidate.

        Person candidate = new Person("Jone","2");

        Console.WriteLine("{0}({1}) already on file: {2}.",

                  applicant2.LastName,

                  applicant2.SSN,

                  applicant2.Equals(applicant1));

    }

}

 

三泛型重点之泛型约束

1 泛型约束的概述

泛型约束的作用:对于所定义的泛型类,在客户端代码,可以对其实例化泛型类时所用的类型参数的类型种类施加限制。若在客户端代码中,尝试使用某个约束所不允许的类型来实例化类,则会产生编译错误。

约束的类型有以下六种:

约束

说明

T:结构

类型参数必须是值类型。可以指定除Nullable 以外的任何值类型。

T:类

类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。

T:new()

类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。

T:<基类名>

类型参数必须是指定的基类或派生自指定的基类。

T:<接口名称>

类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。

T:U

为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。

 

2.泛型约束的演练

2.1代码模板:

    class MyList<T> where T:new ()

    {

        List<T> list = new List<T>();

        public T this[int i]

        {

            get { return list[i]; }

            set { this.list[i] = value; }

        }

    }

 

    class Person

    {

        public string Name { get; set; }

    }

2.2指定泛型参数为值类型

(1)根据2.1代码模板,指定泛型类型为值类型。

class MyList<T> where T:struct

{

}

 (2) 在客户端实例化泛型类型:

MyList<Person> list = new MyList<Person>();

出现编译错误,提示:

类型“GencConstraint.Person”必须是不可为 null 的值类型才能用作泛型类型或方法“GencConstraint.MyList<T>”中的参数“T”。

(3) 在客户端使用如下方式的实例化,将一切正常:

MyList<int> list = new MyList<int>();

2.3指定泛型参数为引用类型

(1)根据2.1代码模板,指定泛型类型为引用类型。

class MyList<T> where T:class

{

}

(2)在客户端使用如下方式的实例化,将一切正常:

MyList<Person> list = new MyList<Person>();

(3)在客户端使用如下方式的实例化,出现编译错误:

MyList<int> list = new MyList<int>();

2.4指定泛型参数为无参的公共的构造函数

(1)根据2.1代码模板,指定泛型类型如下:

class MyList<T> where T:new()

{

}

(2)为Person类指定私有构造函数:

class Person

{

         public string Name { get; set; }

         private Person()

         {

             //do nothing

         }

}

 出现编译错误,提示:

“GencConstraint.Person”必须是具有公共的无参数构造函数的非抽象类型,才能用作泛型类型或方法“GencConstraint.MyList<T>”中的参数“T”。

2.5指定泛型参数必须派生于指定基类

(1)新增基类:

    abstract class SeniorAnimal//高级动物

    {

        public abstract void Speak();//会说话

    }

 (2)根据2.1代码模板,指定泛型参数必须派生于基类SeniorAnimal:

class MyList<T> where T: SeniorAnimal

{

}

(3) 在客户端实例化泛型类型:

MyList<Person> list = new MyList<Person>();

出现编译错误,提示:

不能将类型“GencConstraint.Person”用作泛型类型或方法“GencConstraint.MyList<T>”中的类型参数“T”。没有从“'GencConstraint.Person”到“GencConstraint.SeniorAnimal”的隐式引用转换。

(4)修改代码,使Person类继承自SeniorAnimal类:

    class Person : SeniorAnimal

    {

        public string Name { get; set; }

 

        public override void Speak()

        {

            Console.WriteLine("我会说英语!");

        }

    }

则编译成功。

2.6指定泛型参数必须实现指定接口。

示例同2.4,不再讲述。

2.7指定泛型参数必须派生于泛型类型U(裸类型约束)

格式如下:

class MyList<U> where U : SeniorAnimal

{

        List<U> list = new List<U>();

         public void ShowInfo<T>() where T : U

         {

         }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值