泛型------《转载》 泛型

泛型

1, 什么是泛型?

       在理解泛型的定义之前,我们要明白非泛型的概念,非泛型就是大部分情况下是声明一个类,然后封装需要的行为,最后创建这些类的实例。

       泛型是一种更准确地使用有一种以上的类型的代码的方式。泛型允许我们声明类型参数化的代码,我们可以用不同的类型进行实例化。总结为一句话就是,泛型类型是类型的模板。

       请仔细理解下面两张图,或许能更好地理解泛型的原理。

2, 泛型类?

       创建和使用常规的,非泛型的类的过程有两个步骤:声明类和创建类的实例。

       泛型的类不是实际的类,而是类的模板,所以我们必须先从它们构建实际的类类型, 然后个构建后的类类型的实例。

       下图演示了泛型类的创建过程:

3, 声明泛型类?

       声明一个泛型类和声明普通类差不多,主要有如下区别:

1>    在类名之后放置一组尖括号。

2>    在尖括号中用逗号分隔的占位符字符串来表示希望提供的类型。这叫类型参数(Type Parameter)

3>    在泛型类声明的主体中使用类型参数来表示应该被替代的类型。

如下代码所示声明了一个SomeClass的泛型类:

复制代码

 class SomeClass<T1, T2> //声明泛型类SomeClass,尖括号中是类型参数。

{

public T1 SomeVar = new T1(); //通常在这些位置使用类型。

}

复制代码

     注:泛型和非泛型区分的最主要的标志是:泛型类有尖括号。

4, 创建构造类型?

       我们不能直接从泛型类型创建实例对象。首先,我们需要告诉编译器使用哪些真实类型来替代占位符(类型参数)。编译器获取这些真实类型并从它创建一个真实类型对象。

       创建构造类型例如:

SomeClass<short,int> //尖括号中为类型实参

5, 创建泛型类的变量和实例?

       创建泛型类实例一般有两种方法:

       方法一:和普通非泛型类的对象创建方法相似

SomeClass<short, int> mySc1 = new SomeClass<short, int>(); //第一种方法创建泛型类实例。

      方法二:使用Var关键字隐式创建:

var mySc2 = new SomeClass<short, int>(); //第二种方法,使用Var关键字创建。

      例如:

复制代码

         class Program

{

static voidMain(string[] args)

{

var stackInt = new MyStack<int>(); //创建泛型类对象(或称实例),创建构造类型和创建实例可以一步完成。

var stackString=new MyStack<String>();



stackInt.Push(3); //调用方法

stackInt.Push(5);

stackInt.Push(7);

stackInt.Print();



stackString.Push("Generics are great!");

stackString.Push("Hi there");

stackString.Print();



Console.ReadKey();

}

}

class MyStack<T> //声明泛型类

{

T[] StackArray; //声明数组

int StackPointer = 0; //声明并初始化整形变量。

public void Push(T x) //定义无返回值方法

{

if (!IsStackFull)

{

StackArray[StackPointer++] = x; //为数组StackArray赋值。

}

}

public T Pop() //定义有返回值方法

{

return (!IsStackEmpty) //条件运算符,可以用if...else...语句等价表示。

? StackArray[--StackPointer]

: StackArray[0];

}

public MyStack() //构造函数初始化数组StackArray,为数组分配内存引用。

{

StackArray=new T[MaxStack];

}

public void Print() //构造函数

{

for (int i = StackPointer - 1; i >= 0; i--)

{

Console.WriteLine("Value:{0}",StackArray[i]);

}

}



const int MaxStack = 10; //声明并初始化常量MaxStack

bool IsStackFull //声明属性

{

get { return StackPointer >= MaxStack; }

}

bool IsStackEmpty //声明属性

{

get { return StackPointer <= 0; }

}

}

复制代码

     程序输出结果为:

       附:泛型栈和非泛型栈之间的区别总结如下图表:

非泛型

泛型

源代码大小

更大:我们需要为每种类型进行一个新的实现。

更小:不管构造类型的数量多少,我们只需要一个实现。

可执行大小

无论每一个版本的栈是否会被使用,都会在编译的版本中出现。

可执行文件中只会出现有构造类型的类型。

写的难易度

易于书写

比较难写

维护的难易度

更容易出问题,因为所有修改需要应用到每一个可用的类型上。

易于维护,因为只需要修改一个地方。

6, 泛型结构?

       例如:

复制代码

       struct PieceOfData<T> //声明泛型结构

{

public PieceOfData(T value) //构造函数,初始化字段_Data。

{

_Data = value;

}

private T _Data;//声明私有字段(只能在类的内部访问)。

public T Data //声明属性

{

get { return _Data; }

set { _Data = value; }

}

}



class Program

{

static voidMain()

{

var intData=new PieceOfData<int>(10);//创建构造类型实例

var stringData=new PieceOfData<string>("Hi there!");



Console.WriteLine("intData={0}",intData.Data);//访问属性

Console.WriteLine("stringData={0}",stringData.Data);

Console.ReadKey();

}

}

复制代码

      程序输出结果为:

7, 泛型接口?

       泛型接口的声明和非泛型接口的声明差不多,但是需要在接口名称之后的尖括号中有类型参数。

       例如:

复制代码

    interface IMyIfc<T> //声明泛型接口,尖括号中为类型参数。

{

T ReturnIt(T inValue); //声明返回值类型为T的方法

}



class Simple<S> : IMyIfc<S> //声明泛型类,实现了泛型接口。

{

public S ReturnIt(S inValue) //实现接口成员方法。

{

return inValue;

}

}



class Program

{

static voidMain(string[] args)

{

var trivInt = new Simple<int>(); //创建构造类型实例。尖括号中为类型实参。

var trivString = new Simple<string>();



Console.WriteLine("{0}",trivInt.ReturnIt(50)); //调用类对象实现的方法。

Console.WriteLine("{0}",trivString.ReturnIt("Hi there!"));



Console.ReadKey();

}

}

复制代码

      程序输出结果为:

8, 泛型委托?

1>    要声明泛型委托,在委托名称之后,委托参数列表之前的尖括号中放类型参数列表。

2>    注意,在这里泛型委托有两个参数列表:委托形参列表和类型参数列表。

例如:

复制代码

delegate void MyDelegate<T>(T value); //声明泛型委托



class Simple

{

public static void PrintString(string s) //方法匹配委托,

{

Console.WriteLine(s);

}



public static void PrintUpperString(string s)

{

Console.WriteLine("{0}", s.ToUpper());//调用string的ToUpper方法实现将字符串转换为大写。

}

}



class Program

{

static voidMain(string[] args)

{

var MyDel = new MyDelegate<string>(Simple.PrintString); //创建委托的实例

MyDel += Simple.PrintUpperString; //为委托添加方法。

if (null != MyDel) //判断委托是否为空。

{

MyDel("VinceInfo");//调用委托。

}

else

{

Console.WriteLine("Delegate is empty!");

}

Console.ReadKey();

}

}

复制代码

     程序输出结果如下:

9, 泛型方法?

       泛型方法和泛型委托相似,有两个参数列表:

1>    封闭在圆括号内的方法参数列表。

2>    封闭在尖括号内的类型参数列表。

例如:

复制代码

class Simple //非泛型类

{

static public void ReverseAndPrint<T>(T[] arr) //声明泛型方法

{

Array.Reverse(arr);

foreach (T item in arr) //遍历数组。使用类型参数T。

{

Console.Write("{0}",item.ToString());

Console.Write("");

}

Console.WriteLine(); //换行

}

}



class Program

{

static voidMain(string[] args)

{

//创建三种类型的数组。

var intArray = new int[] { 3,5,7,9,11};

var stringArray = new string[] { "first","second","third"};

var doubleArray = new double[] { 3.567,7.891,2.345};



Simple.ReverseAndPrint<int>(intArray); //调用泛型方法,显示调用

Simple.ReverseAndPrint(intArray); //使用推断类型隐式调用。



Simple.ReverseAndPrint<string>(stringArray);

Simple.ReverseAndPrint(stringArray);



Simple.ReverseAndPrint<double>(doubleArray);

Simple.ReverseAndPrint(doubleArray);



Console.ReadKey();



}

}

复制代码

程序输出结果为:

10,扩展方法和泛型类?

       扩展方法可以和泛型类结合使用,它允许我们将类中的静态方法关联到不同的泛型类上,还允许我们像调用类构造实例的实例方法一样来调用方法。

       例如:

复制代码

       static class ExtendHolder

{

public static void Print<T>(this Holder<T> h) //声明扩展方法并关联到泛型类Holder<T>上。

{

T[] vals = h.GetValues(); //调用泛型类的方法。

Console.WriteLine("{0},\t{1},\t{2}",vals[0],vals[1],vals[2]); //"\t"转义符

}

}



class Holder<T> //声明泛型类

{

T[] vals=new T[3];//声明并初始化数组。

public Holder(T v0, T v1, T v2) //构造函数,为数组赋值。

{

vals[0] = v0;

vals[1] = v1;

vals[2] = v2;

}

public T[] GetValues() //声明方法,返回数组类型。

{

return vals;

}

}



class Program

{

static voidMain(string[] args)

{

var intHolder = new Holder<int>(3,5,7); //创建泛型类实例

var stringHolder = new Holder<string>("a1","b2","c3");



intHolder.Print(); //调用方法

stringHolder.Print();



Console.ReadKey();

}

}

复制代码

     程序输出结果为:

      关于泛型先写到这里,欢迎大家指正,谢谢!

1, 什么是泛型?

       在理解泛型的定义之前,我们要明白非泛型的概念,非泛型就是大部分情况下是声明一个类,然后封装需要的行为,最后创建这些类的实例。

       泛型是一种更准确地使用有一种以上的类型的代码的方式。泛型允许我们声明类型参数化的代码,我们可以用不同的类型进行实例化。总结为一句话就是,泛型类型是类型的模板。

       请仔细理解下面两张图,或许能更好地理解泛型的原理。

2, 泛型类?

       创建和使用常规的,非泛型的类的过程有两个步骤:声明类和创建类的实例。

       泛型的类不是实际的类,而是类的模板,所以我们必须先从它们构建实际的类类型, 然后个构建后的类类型的实例。

       下图演示了泛型类的创建过程:

3, 声明泛型类?

       声明一个泛型类和声明普通类差不多,主要有如下区别:

1>    在类名之后放置一组尖括号。

2>    在尖括号中用逗号分隔的占位符字符串来表示希望提供的类型。这叫类型参数(Type Parameter)

3>    在泛型类声明的主体中使用类型参数来表示应该被替代的类型。

如下代码所示声明了一个SomeClass的泛型类:

复制代码

 class SomeClass<T1, T2> //声明泛型类SomeClass,尖括号中是类型参数。

{

public T1 SomeVar = new T1(); //通常在这些位置使用类型。

}

复制代码

     注:泛型和非泛型区分的最主要的标志是:泛型类有尖括号。

4, 创建构造类型?

       我们不能直接从泛型类型创建实例对象。首先,我们需要告诉编译器使用哪些真实类型来替代占位符(类型参数)。编译器获取这些真实类型并从它创建一个真实类型对象。

       创建构造类型例如:

SomeClass<short,int> //尖括号中为类型实参

5, 创建泛型类的变量和实例?

       创建泛型类实例一般有两种方法:

       方法一:和普通非泛型类的对象创建方法相似

SomeClass<short, int> mySc1 = new SomeClass<short, int>(); //第一种方法创建泛型类实例。

      方法二:使用Var关键字隐式创建:

var mySc2 = new SomeClass<short, int>(); //第二种方法,使用Var关键字创建。

      例如:

复制代码

         class Program

{

static voidMain(string[] args)

{

var stackInt = new MyStack<int>(); //创建泛型类对象(或称实例),创建构造类型和创建实例可以一步完成。

var stackString=new MyStack<String>();



stackInt.Push(3); //调用方法

stackInt.Push(5);

stackInt.Push(7);

stackInt.Print();



stackString.Push("Generics are great!");

stackString.Push("Hi there");

stackString.Print();



Console.ReadKey();

}

}

class MyStack<T> //声明泛型类

{

T[] StackArray; //声明数组

int StackPointer = 0; //声明并初始化整形变量。

public void Push(T x) //定义无返回值方法

{

if (!IsStackFull)

{

StackArray[StackPointer++] = x; //为数组StackArray赋值。

}

}

public T Pop() //定义有返回值方法

{

return (!IsStackEmpty) //条件运算符,可以用if...else...语句等价表示。

? StackArray[--StackPointer]

: StackArray[0];

}

public MyStack() //构造函数初始化数组StackArray,为数组分配内存引用。

{

StackArray=new T[MaxStack];

}

public void Print() //构造函数

{

for (int i = StackPointer - 1; i >= 0; i--)

{

Console.WriteLine("Value:{0}",StackArray[i]);

}

}



const int MaxStack = 10; //声明并初始化常量MaxStack

bool IsStackFull //声明属性

{

get { return StackPointer >= MaxStack; }

}

bool IsStackEmpty //声明属性

{

get { return StackPointer <= 0; }

}

}

复制代码

     程序输出结果为:

       附:泛型栈和非泛型栈之间的区别总结如下图表:

非泛型

泛型

源代码大小

更大:我们需要为每种类型进行一个新的实现。

更小:不管构造类型的数量多少,我们只需要一个实现。

可执行大小

无论每一个版本的栈是否会被使用,都会在编译的版本中出现。

可执行文件中只会出现有构造类型的类型。

写的难易度

易于书写

比较难写

维护的难易度

更容易出问题,因为所有修改需要应用到每一个可用的类型上。

易于维护,因为只需要修改一个地方。

6, 泛型结构?

       例如:

复制代码

       struct PieceOfData<T> //声明泛型结构

{

public PieceOfData(T value) //构造函数,初始化字段_Data。

{

_Data = value;

}

private T _Data;//声明私有字段(只能在类的内部访问)。

public T Data //声明属性

{

get { return _Data; }

set { _Data = value; }

}

}



class Program

{

static voidMain()

{

var intData=new PieceOfData<int>(10);//创建构造类型实例

var stringData=new PieceOfData<string>("Hi there!");



Console.WriteLine("intData={0}",intData.Data);//访问属性

Console.WriteLine("stringData={0}",stringData.Data);

Console.ReadKey();

}

}

复制代码

      程序输出结果为:

7, 泛型接口?

       泛型接口的声明和非泛型接口的声明差不多,但是需要在接口名称之后的尖括号中有类型参数。

       例如:

复制代码

    interface IMyIfc<T> //声明泛型接口,尖括号中为类型参数。

{

T ReturnIt(T inValue); //声明返回值类型为T的方法

}



class Simple<S> : IMyIfc<S> //声明泛型类,实现了泛型接口。

{

public S ReturnIt(S inValue) //实现接口成员方法。

{

return inValue;

}

}



class Program

{

static voidMain(string[] args)

{

var trivInt = new Simple<int>(); //创建构造类型实例。尖括号中为类型实参。

var trivString = new Simple<string>();



Console.WriteLine("{0}",trivInt.ReturnIt(50)); //调用类对象实现的方法。

Console.WriteLine("{0}",trivString.ReturnIt("Hi there!"));



Console.ReadKey();

}

}

复制代码

      程序输出结果为:

8, 泛型委托?

1>    要声明泛型委托,在委托名称之后,委托参数列表之前的尖括号中放类型参数列表。

2>    注意,在这里泛型委托有两个参数列表:委托形参列表和类型参数列表。

例如:

复制代码

delegate void MyDelegate<T>(T value); //声明泛型委托



class Simple

{

public static void PrintString(string s) //方法匹配委托,

{

Console.WriteLine(s);

}



public static void PrintUpperString(string s)

{

Console.WriteLine("{0}", s.ToUpper());//调用string的ToUpper方法实现将字符串转换为大写。

}

}



class Program

{

static voidMain(string[] args)

{

var MyDel = new MyDelegate<string>(Simple.PrintString); //创建委托的实例

MyDel += Simple.PrintUpperString; //为委托添加方法。

if (null != MyDel) //判断委托是否为空。

{

MyDel("VinceInfo");//调用委托。

}

else

{

Console.WriteLine("Delegate is empty!");

}

Console.ReadKey();

}

}

复制代码

     程序输出结果如下:

9, 泛型方法?

       泛型方法和泛型委托相似,有两个参数列表:

1>    封闭在圆括号内的方法参数列表。

2>    封闭在尖括号内的类型参数列表。

例如:

复制代码

class Simple //非泛型类

{

static public void ReverseAndPrint<T>(T[] arr) //声明泛型方法

{

Array.Reverse(arr);

foreach (T item in arr) //遍历数组。使用类型参数T。

{

Console.Write("{0}",item.ToString());

Console.Write("");

}

Console.WriteLine(); //换行

}

}



class Program

{

static voidMain(string[] args)

{

//创建三种类型的数组。

var intArray = new int[] { 3,5,7,9,11};

var stringArray = new string[] { "first","second","third"};

var doubleArray = new double[] { 3.567,7.891,2.345};



Simple.ReverseAndPrint<int>(intArray); //调用泛型方法,显示调用

Simple.ReverseAndPrint(intArray); //使用推断类型隐式调用。



Simple.ReverseAndPrint<string>(stringArray);

Simple.ReverseAndPrint(stringArray);



Simple.ReverseAndPrint<double>(doubleArray);

Simple.ReverseAndPrint(doubleArray);



Console.ReadKey();



}

}

复制代码

程序输出结果为:

10,扩展方法和泛型类?

       扩展方法可以和泛型类结合使用,它允许我们将类中的静态方法关联到不同的泛型类上,还允许我们像调用类构造实例的实例方法一样来调用方法。

       例如:

复制代码

       static class ExtendHolder

{

public static void Print<T>(this Holder<T> h) //声明扩展方法并关联到泛型类Holder<T>上。

{

T[] vals = h.GetValues(); //调用泛型类的方法。

Console.WriteLine("{0},\t{1},\t{2}",vals[0],vals[1],vals[2]); //"\t"转义符

}

}



class Holder<T> //声明泛型类

{

T[] vals=new T[3];//声明并初始化数组。

public Holder(T v0, T v1, T v2) //构造函数,为数组赋值。

{

vals[0] = v0;

vals[1] = v1;

vals[2] = v2;

}

public T[] GetValues() //声明方法,返回数组类型。

{

return vals;

}

}



class Program

{

static voidMain(string[] args)

{

var intHolder = new Holder<int>(3,5,7); //创建泛型类实例

var stringHolder = new Holder<string>("a1","b2","c3");



intHolder.Print(); //调用方法

stringHolder.Print();



Console.ReadKey();

}

}

复制代码

     程序输出结果为:

      关于泛型先写到这里,欢迎大家指正,谢谢!

猜你喜欢

转载自www.cnblogs.com/bedfly/p/11898944.html