泛型概述

首先我们看一个在泛型出现之前通用的数据结构示例

通用数据结构类

Code
public class Stack
{
    object[] m_Items;
    public Stack()
    { }
    public void Push(object item)
    { }
    public object Pop()
    { }
}

调用实例

Code
public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Stack stack = new Stack();
        stack.Push(1);//装箱
        stack.Push(2);//装箱
        int number = (int)stack.Pop();//拆箱
    }
}

然后我们看看基于上面object解决方案存在的问题

1.由于在实际调用的时候会频繁出现值类型的装箱、拆箱,这将会导致很多垃圾碎片,增加垃圾收集的负担;对于引用类型这方面的问题也不容小觑

2.编译时任务类型都可以转换成object,无法保证运行时类型的安全。请看下面代码所示,编译可通过,运行时报错:

Code
public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Stack stack = new Stack();
        stack.Push("test");

//这句显然是错误的,但编译可以通过
        int number = (int)stack.Pop();
    }
}

那么有人提出了,既然通用数据结构类用object类型不行,那我可以用特定类型来替换上面结构类中的object类型,来处理特定类型的Stack,这样虽然解决了上面两个问题,但又会出现如下问题:

1.影响工作效率。

因为你首先要预知有好多个特定类型要使用上面通用结构类,然后要根据这些不同的类型写不同的class

2.代码冗余,复用率很低,这是显而易见的

3.一个数据结构的变更要将所有类型的数据结构做相应的修改。

因为要修改所有基于这个数据结构来实现的特定类型的数据结构

4.为了提供不可预知的数据类型的支持,还是要提供object类型接口,这样老问题又会出现

针对上面出现的问题,似乎在原来是没办法解决的问题,但在2.0以后微软推出泛型这一数据结构,可以很好的解决上面的问题。

什么是泛型?

通过泛型可以定义类型安全类,而不损害类型安全、性能或工作效率,我们可以将下面的结构类

Code
public class Stack
{
    object[] m_Items;
    public Stack()
    { }
    public void Push(object item)
    { }
    public object Pop()
    { }
}

修改为

Code
public class Stack<T>
{
    T[] m_Items;
    public Stack()
    { }
    public void Push(T item)
    { }
    public T Pop()
    { }
}

运行时实例化

1.可以使用任何类型声明和实例化

2.声明和实例化是都必须使用一个特定类型来代替一般类型

3.泛型编程模型的优点是:内部算法和操作保持不变,而实际类型可以在使用时指定

Code
public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Stack<int> stack = new Stack<int>();
        stack.Push(1);
        stack.Push(2);

int number = stack.Pop();
    }
}

泛型是如何实现的?

1.在.Net2.0中,泛型在IL和CLR本身中具有本机支持

2.编译类型时,就像编译其他类型一样,泛型仅保留一个占位符

3.而用特定类型实例化泛型代码,编译时会将泛型替代为特定的实际类型

泛型的好处

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

2.编译器支持和类型安全

3.不会强行对值类型进行装箱和拆箱,或者对引用类型进行向下强制类型转换,所以性能得到显著提高。对于值类型,一般提高200%,对于引用类型,也可提高100%(当然整个应用程序的运行效率也可能会提高,也可能不会提高)。

在结构体中使用泛型

定义通用结构体

Code
public struct Point<T>
{
    public T x;
    public T y;
}

运行实例

Code
 Point<int> point;
 point.x = 1;
 point.y = 2;
Code
Point<double> point;
point.x = 1.2;
point.y = 2.3;

default方法

在针对上面的泛型通用结构类中,如果你不希望在堆栈为空时引发异常,而是希望返回堆栈中存储类型的默认值,就要使用到default方法。此方法主要用于将获取泛型编程模型中的泛型类型参数的默认值

-default(ValueType)=0;

-default(ReferenceType)=null;

举例说明:如上面Stack<T>,用default(T)获取默认值。

多个泛型

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

比如Custom<K,T>,Custom为类型,K为此类型的第一个泛型,T为第二个泛型,若更多的话用,隔开。

泛型别名

在文件头部使用using关键字为特定类型取别名

别名作用范围是整个文件,具体实现

Code
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Stack = Stack<int>;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Stack stack = new Stack();
        stack.Push(1);
        stack.Push(2);

int number = stack.Pop();
    }
}

泛型约束-派生约束

为什么要使用泛型约束,先看下面方法

public class LinkedList

{

T Find(K key)

{

Node<K,T> current = m_Head;

while(current.NextNode!=null)

{

//因为编译器不知道K类型的key是否支持"=="运算符,例如在默认情况,结构体就不提供这种实现

if(current.Key==key) //Will not Compile

{

break;

}

else

{

current=current.NextNode;

}

}

return current.Item;

}

}

根据上面注释得知,此方法是不会通过编译的,那么采取什么方法来解决呢,我们就想到了IComparable下面的CompareTo方法,如下:

public interface IComparable

{

int CompareTo(object obj);

}

解决方案如下:

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

{

T Find(K key)

{

Node<K,T> current = m_Head;

while(current.NextNode!=null)

{

//因为编译器不知道K类型的key是否支持"=="运算符,例如在默认情况,结构体就不提供这种实现

if(current.Key.CompareTo(key)==0) //Will not Compile

{

break;

}

else

{

current=current.NextNode;

}

}

return current.Item;

}

}

注:1.where关键字,若上类中的K和T都要约束,那么两个where之间用空格隔开

2.K:IComparable表示K只接受实现了IComparable接口的类型

3.尽管如此,还是无法避免传入值类型的K所带来的装箱问题,原因是IComparable下的CompareTo方法的参数仍是object类型。所以最终的正确代码如下:

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

{

T Find(K key)

{

Node<K,T> current = m_Head;

while(current.NextNode!=null)

{

//因为编译器不知道K类型的key是否支持"=="运算符,例如在默认情况,结构体就不提供这种实现

if(current.Key.CompareTo(key)==0) //Will not Compile

{

break;

}

else

{

current=current.NextNode;

}

}

return current.Item;

}

}

注意:

1.在C#2.0中,所有的派生约束必须放在类的实际派生列表之后

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

{......}

2.通常只需要在需要的级别定义类的约束,即:哪里编译异常哪里约束。

3.一个泛型参数上约束多个接口(彼此用,分隔)

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

{......}

4.在一个约束中最多只能有一个基类,同时约束的基类不能是密封类或静态类,因为密封类不能被继承,静态类不能被实例化。

5.不能将System.Delegate或System.Array作为泛型基类

6.可以同时约束一个基类和一个或多个接口,但是基类必须首先出现在约束列表中

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

{......}

7.C#允许你将另一个一般类型指定为约束

public class LinkeList<K,T> where K:T

{......}

8.自定义基类或接口进行泛型约束

自定义接口

public interface IMyInterface

{......}

public class MyClass<T> where T:IMyInterface

{......}

MyClass<IMyInterface> obj=new MyClass<IMyInterface>();

自定义基类

public class MyOtherClass

{......}

public class MyClass<T> where T:MyOtherClass

{......}

MyClass<MyOtherClass> obj=new MyClass<MyOtherClass>();

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

正确的可见性

public class MyBaseClass

{......}

internal class MySubClass<T> where T:MyBaseClass

{......}

错误的可见性

internal class MyBaseClass

{......}

public class MySubClass<T> where T:MyBaseClass

{......}

泛型约束-构造函数约束

假设你要在一个一般类的内部实例化一个新的一般对象。问题在于,C#编译器不知道客户将要使用的类型实参是否具有匹配的构造函数,因而它拒绝编译实例化行。

为了解决该问题,C#运行约束一般类型参数,以使其必须支持公共支持的默认构造函数这是使用new()约束来完成的

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

{

public K key;

public T item;

public Node<K,T> NextNode;

public Node()

{

key=default(K);

item=new T();

NextNode=null;

}

}

注意:

可以将构造函数和派生约束混合起来,前提是构造函数约束要放到约束列表的最后

public class LinkedList<K,T> where K:IComparable<K>,new()

{......}

泛型约束-值/引用类型约束

可以使用struct约束将一般类型参数约束为值类型(例如:int,bool和enum),或任何自定义结构

public class MyClass<T> where T:struct

{......}

可以使用class约束将一般类型参数约束为引用类型(类)

public class MyClass<T> where T:class

{......}

注意

1.不能将引用/值类型约束与基类约束一起使用,因为基类约束涉及到类。

2.不能使用结构和默认构造函数约束,因为默认构造函数约束也涉及到类。

3.虽然你可以使用类和默认构造函数约束,但是这样做没有任何意义。

4.可以将引用/值类型约束与接口约束组合起来,前提是引用/值类型约束必须放在约束列表的开头。

转载于:https://www.cnblogs.com/jewleo/archive/2009/06/07/06071638_1.html

【整理】C#2.0泛型编程之概述、default()方法、别名指定与泛型约束相关推荐

  1. Servlet 3.0 新特性概述

    Servlet 3.0 新特性概述 Servlet 3.0 作为 Java EE 6 规范体系中一员,随着 Java EE 6 规范一起发布.该版本在前一版本(Servlet 2.5)的基础上提供了若 ...

  2. UltraDefrag(磁盘碎片整理工具) v8.0.1中文绿色便携版

    点击下载来源:UltraDefrag(磁盘碎片整理工具) v8.0.1中文绿色便携版 UltraDefrag是国外一款十分强大的磁盘碎片整理工具,它能够帮助用户轻松快捷的整理磁盘碎片,软件使用内核模式 ...

  3. C# 2.0 泛型编程

    C#泛型演示说明:此文章来源于: http://blog.csdn.net/shoutor/ using System; using System.Collections.Generic; using ...

  4. C# 2.0 泛型编程 选择自 shoutor 的 Blog

    C# 2.0 泛型编程     选择自 shoutor 的 Blog 关键字   C# 2.0 泛型编程 出处   C#泛型演示 class Stack<T> {    private T ...

  5. DiskTrix UltimateDefrag(磁盘碎片整理软件) v6.0.22.0破解版

    点击下载来源:DiskTrix UltimateDefrag(磁盘碎片整理软件) v6.0.22.0破解版 UltimateDefrag 6是一款全新的磁盘碎片整理软件,在新版本中有着多方面的改进与优 ...

  6. UltimateDefrag磁盘碎片整理软件 v3.0.100.19汉化版

    软件名称:UltimateDefrag磁盘碎片整理软件 v3.0.100.19汉化版 软件类别:汉化软件 运行环境:Windows 软件语言:简体中文 授权方式:免费版 软件大小:3.25 MB 软件 ...

  7. SOME/IP协议详解「2.0·服务化通信概述」

    SOME/IP协议详解「2.0·服务化通信概述」 点击返回雪云飞星的SOME/IP协议详解「总目录」 SOME/IP协议详解「2.0·服务化通信概述」 1 SOME/IP服务的组成 2 Method| ...

  8. ultimatedefrag 6汉化版(磁盘碎片整理) v6.0.62.0

    大家在使用电脑的时候经常会下载各种软件,有些用户在使用过后通常会把软件给删除,可是在删除的时候总会有些文件删不干净,而这时就可以试试ultimatedefrag 6,这是由DiskTrix公司开发的一 ...

  9. 王姨劝我学HarmonyOS鸿蒙2.0系列教程之五布局方法点击响应!

    原创PDF |<Android 深入系统完全讲解>免费开源,可能价值百万! 王姨劝我学HarmonyOS鸿蒙2.0系列教程之三Ability概述&&调用方法! 为了更好的交 ...

最新文章

  1. SourceTree的基本使用
  2. mysql bitmap redis_Redis中bitmap的妙用
  3. java 同步的方法_关于Java中的同步方法
  4. 在c语言中定义共用型数据类型的关键字是,C语言的关键字共有32个,根据关键字的作用,可分其为数据类型关键...
  5. 《自顶向下网络设计(第3版)》——2.7 适应性
  6. eclipse 配置多个tomcat
  7. 提升效率小工具,我用30分钟就干完一天的活
  8. 2020-09-30
  9. Vivado:信道编码卷积编码和RS编码IP核
  10. Win10任务栏无响应解决方法集锦
  11. 3款超好用的音频剪辑软件,功能全面,操作简单!
  12. 管道 pipe是什么?(进程通信的一种方式)
  13. python+appium在使用swipe滑动时,报错The swipe did not complete successfully的解决办法
  14. Perfmon - Windows 自带系统监测工具
  15. 【AI绘画】绝美春天插画,人人都是插画师
  16. IAM统一身份认证服务
  17. MySQL之流程函数
  18. 【Python+C#】手把手搭建基于Hugging Face模型的离线翻译系统(如果你想,也可以在线)
  19. 对AutoCompleteTextBox的扩展
  20. RPG游戏人物视角控制,相机跟随

热门文章

  1. mac常用设置(新建、显示隐藏文件、任意位置开启终端等)
  2. 算法---回溯法--模板解法
  3. 【零基础学Java】—继承父类并实现多个接口(二十五)
  4. 【jQuery学习】—实现弹幕效果
  5. HTML+CSS+JS实现网页随机点名
  6. 力扣 根据数字二进制下1的数目排序
  7. 18岁参加工作,工龄30年
  8. python%20是什么运算
  9. 赤小豆和红小豆有什么区别,哪种和薏米煮粥更好些?
  10. 巴菲特曾说过,如果一个人身上有以下几个恶习