当前位置:K88软件开发文章中心编程语言.NET.NET01 → 文章内容

关于C#泛型

减小字体 增大字体 作者:佚名  来源:翔宇亭IT乐园  发布时间:2018-12-31 11:55:33

:2010-08-28 07:48:00

C#提供了一个非常方便的东西——泛型,那么什么是泛型,泛型有哪些好处,如何使用泛型?下面就做一个详细的介绍:

1、什么是泛型?

通过泛型可以定义类型安全类,而不会损害类型安全、性能或工作效率

2、实例化泛型

(1)可以使用任何类型来声明和实例化

(2)申明和实例话都必须用一个特定的类型来代替一般类型T

(3)举例说明:

//原来写法
Public class Stack
{
     object[] m_Items; 
     public void Push(object item) 
     {...} 
     public object Pop() 
     {...}
}
Stack stack = new Stack();
stack.Push(1);
int number = (int)stack.Pop();

//有了泛型后
Public class Stack <T>

     T[] m_Items; 
     public void Push(T item) 
     {...} 
     public T Pop() 
     {...}
}
Stack <int> stack = new Stack <int> ();
stack.Push(1);
int number = (int)stack.Pop();

3、泛型的好处

(1)一次性的开发、测试和部署代码,通过任何类型来重用它

(2)编译器支持和类型安全

(3)不会强行对值类型进行装箱和取消装箱,或者对引用类型进行向下强制类型转换,所以性能得到显著提高。

 注:值类型大概可以提高200%,引用类型大概为100%

4、多个泛型

单个类型可以定义多个泛型

5、泛型别名

(1)在文件头部使用using 为特定类型取别名,别名作用范围是整个文件

(2)举例说明

using List = LinkedList <int,string> ;
class ListClient

     static void Main(string[] args) 
     { 
          List list = new List(); 
          list.AddHead(123, "AAA "); 
     }
}

6、泛型约束

A 派生约束

如:

public class LinkedList <K,T> where K:IComparable
{
T Find(K key)
{
if (str.Key.CompareTo(key) == 0)//只有实现这个接口才可比较
}
}

注意:

(1)所有的派生约束必须放在类的实际派生列表之后

如:public class LinkedList <K,T> :IEnumerable <T> where K:IComparable <K> {...}

(2)一个泛型参数上可以约束多个接口(用逗号分隔)

public class LinkedList <K,T> where K:IComparable <K> ,IConvertible

(3)在一个约束中最多只能使用一个基类

(4)约束的基类不能是密封类或静态类

(5)不能将System.Delegate或System.Array约束为基类

(6)可以同时约束一个基类以及一个或多个接口,但是该基类必须首先出现在派生约束列表中。

(7)C#允许你将另一个泛型参数指定为约束

public class MyClass <T,U> where T:U
        {...}

(8)可以自己定义基类或接口进行泛型约束

(9)自定义的接口或基类必须与泛型具有一致的可见性

B构造函数约束

如:

class Node <K,T> where T:new()
       {
      }

注意:

可以将构造函数的约束和派生约束结合起来,前提是构造函数的约束出现在约束列表中的最后

C引用/值类型约束

(1)可以使用struct约束将泛型参数约束为值类型(如int、bool、enum),或任何自定义结构

(2)同样可以使用class约束将泛型参数约束为引用类型

(3)不能将引用/值类型约束与基类约束一起使用,因为基类约束涉及到类

(4)不能使用结构和默认构造函数约束,因为默认构造函数约束也涉及到类

(5)虽然您可以使用类和默认构造函数约束,但是这样做没有任何价值

(6)可以将引用/值类型约束与接口约束组合起来,前提是引用/值类型约束出现在约束列表的开头

:2010-08-28 07:48:00

7、泛型和强制类型转换

(1)C#编译器只允许将泛型参数隐式转换到Object或约束指定的类型

如:

interface IS{...}
class BaseClass{...}
class MyClass <T> where T:BaseClass,IS
{
void SomeMethod(T t)
{
IS obj1 = t;
BaseClass obj2 = t;
object obj3 = t;
}
}

(2)编译器允许你将泛型参数显示强制转换到其他任何借口,但不能将其转换到类

interface IS{...}
class SomeClass{...}
class MyClass <T> //没有约束
{
void SomeMethod(T t)
{
IS obj1 = (IS)t; //可以
SomeClass obj2 = (SomeClass)t //不可以
}
}

(3)可以使用临时的Object变量,将泛型参数强制转换到其他任何类型

class SomeClass{...}
class MyClass <T>
{
void SomeMethod(T t)
{
object temp = t;
SomeClass obj = (SomeClass)temp;//可以
}
}

注意:这里只是告诉你这样写是可以的,但是要不要这样写?不要这样写,因为如果t确实没有继承SomeClass编译没错但是运行就会出错

(4)解决上面强制转换问题,可以使用is和as运算符进行判断

public class MyClass <T>
{
public void SomeMethod <T t>
{
if (t is int ){...}
if (t is LinkedList <int,string> ){...}
//如果泛型参数的类型是所查询的类型,则is运算符返回true
string str = t as string;
//如果这写类型兼容,则as将执行强制类型转换,否则将返回null
if (str != null){...}
LinkedList <int,string> list = t as LinkedList <int,string> ;
if (list != null){...}
}
}

8、继承和泛型

(1)在从泛型基类派生,可以提供类型实参,而不是基类泛型参数

public class BaseClass <T> {...}

public class SubClass:BaseClass <int>

(2)如果子类是泛型,而非具体的类型实参,则可以使用子类泛型参数作为泛型基类的指定类型

public class BaseClass <TT> {...}

public class SubClass <T> :BaseClass <T> {...}

(3)在使用子类泛型参数时,必须在子类级别重复在基类级别规定的任何约束

(4)基类可以定义其签名使用泛型参数的虚礼方法,在重写它们时,子类必须在方法签名中提供相应的类型。

如:

public class BaseClass <T>
{
public virtual T SomeMethod()
{...}
}
public class SubClass:BaseClass <int>
{
public override int SomeMethod()
{...}
}

(5)如果该子类是泛型,则它还可以在重写时使用它自己的泛型参数

public class SubClass <T> :BaseClass <T>
{
public override T SomeMethod()
{...}
}

(6)你可以定义泛型接口、泛型抽象类,甚至泛型抽象方法。

(7)不能对泛型参数使用+或+=之类的运算符

public class Calculator <T>
{
public T Add (T arg1,T arg2)
{
return arg1 + arg2;//错误
}
}

但是我们可以通过泛型抽象类、接口来实现在个功能,因为实现泛型抽象类、接口我们就已经明确传一个参数了,就可以执行诸如+这样的操作。

9、泛型方法

(1)方法可以定义特定于其执行范围的泛型参数

public class MyClass <T>
{
public void MyMethod <X> (X x)
{...}
}

(2)即使各包含类根本不使用泛型,你也可以定义方法特定的泛型参数

public class MyClass
{
public void MyMethod <T> (T t)
{...}
}

注意:该功能只使用于方法,属性,索引器只能使用在类的作用范围中定义的泛型参数。

(3)调用泛型方法

MyClass obj = new MyClass();

obj.MyMethod <int> (3);

也可以这样:

MyClass obj = new MyClass();

obj.MyMethod(3); //该功能称为泛型推理

(4)泛型方法也可以有自己的泛型参数约束

pubic class MyClass
{
public void SomeMethod <T> (T t) where T:IComparable <T>
{...}
}

(5)子类方法实现不能重复在父级别出现的约束
public class BaseClass
{
public virtual void SomeMethod <T> (T t)where T:new()
{...}
}
pubic class SubClass:BaseClass
{
public override void SomeMethod <T> (T t)//不能再有约束
{...}
}

(6)静态方法

静态方法可以定义特定的泛型参数和约束

public class MyClass <T>
{
public static T SomeMethod <X> (T t,X x)
{...}
}

int number = MyClass <int> .SomeMethod <string> (3, "AAA ");

或者:int mumber = MyClass <int> .SomeMethod(3, "AAA ");

10、泛型委托

(1)在某个类中定义的委托可以利用该类的泛型参数

(2)委托也可以定义自己的泛型参数


上一页  [1] [2] 


关于C#泛型