1、泛型类的功能:在创建泛型类时,还需要一些其他C#关键字。例如,不能把null赋予泛型类型。此时,可以使用default 关键字。如果泛型类型不需要Object类的功能,但需要调用泛型类上的某特定方法,就可以定义约束。

 具体讨论以下:

  • 默认值
  • 约束
  • 继承
  • 静态成员

例:下面是一个使用 泛型文档管理器示例。DocumentManager

  •  using System;
    using System.Collections.Generic;
    namespace Jandar.Test.YinXi{
    public class DocumentManager<T>{
    private readonly Queue<T> documentQueue=new Queue<T>();
    public void AddDocument(T doc){
    lock(this){
    documentQueue.Enqueue(doc);
    }
    }
    public bool IsDocumentAvailable{
    get{
    return documentQueue.Count>;
    }
    }
    }

除了IEnumerable 接口,还有一个泛型版本 IEnumerable<T>。IEnumerable<T> 派生自IEnumerable 添加了IEnumerator<T> 的GetEnumerator() 方法,LinkeedList<T>实现泛型接口 IEnumerable<T>

  【默认值】

    给DocumentManager<T>类添加一个 GetDocument() 方法。在这个方法中,应把 类型T 指定为null。但是,不能把null 赋予泛型类型。原因是泛型类型也可以实例化为值类型,而null 只能用于引用类型。为了解决这个问题,可以使用 default 关键字。通过default 关键字,将null 赋予引用类型,将 0 赋予值类型。

  •   

     public T GetDocument()
    {
    T doc =default(T);
    lock(this)
    {
    doc=documentQueue.Dequeue();
    }
    return doc;
    }

    default 关键字根据上下文可以有多种含义。 switch 语句使用 default 定义默认情况。在泛型中,根据泛型类型是引用类型还是值类型,泛型default 用于将泛型类型初始化为 null 或 0;

  【约束】

  • Document 类实现带有 Title 和Content属性的 IDocument 接口。

     public interface IDocument
    {
    string Title {get; set;}
    string Content{get; set;}
    } public class Document: IDocument
    {
    public Document()
    { }
    public Document(string title,string content)
    {
    this.Title=title;
    this.Content=content;
    }
    public string Title{ get; set;}
    public string Content{getl;set;}
    }
  • 要使用DocumentManager<T> 类显示文档,可以将类型 T 强制转换为 IDocument 接口,以显示标题 title 或者 内容 content
  •  public void DisplayAllDocuments()
    {
    foreach(T doc in documentQueue)
    {
    Console.WriteLine(((IDocument)doc).Title);
    }
    }
  • 问题是如果类型T没有实现IDocument 接口,这个类型强制转换就会导致一个运行异常。最好给DocumentManager<TDocument>类定义一个约束: TDocument 类型必须实现 IDocument 接口,
  •  public class DocumentManager<TDocument> where TDocument : IDocument
    {
    ...
    }
    约束 说明

    where T : struct

    对于结构约束,类型 T 必须是值类型

    where T : class

    类约束指定类型 T 必须是引用类型

    where T : IFoo

    指定类型 T 必须实现接口 IFoo

    where T : Foo

    指定类型 T 必须派生自基类 Foo

    where T : new()

    这是一个构造函数约束,指定类型 T 必须有一个默认构造函数

    where T1 : T2

    这个约束也可以指定,类型T1 派生自 泛型类型T2。 该约束也成为裸类型约束

    只能为默认构造函数定义构造函数约束,不能为其他构造函数定义构造函数约束

    使用泛型类型还可以合并多个约束。 where T :IFoo,new() 约束和 MyClass<T>声明指定,类型T 必须实现IFoo 接口,且必须有一个默认构造函数。

    •       

      public class MyClass<T> where T :IFoo, new()
      {
      ...
      }

   【继承】

   可以定义一个抽象的泛型基类,它在派生类中用一个具体的类型实现。

    •       

       public abstract class Calc<T>
      {
      public abstract T Add(T x, T y);
      public abstract T Sub(T x, T y);
      } public class IntCalc :Calc<int>
      {
      public override int Add(int x ,int y)
      {
      return x+y;
      }
      public override int Sub(int x, int y)
      {
      return x-y;
      }
      }

    【静态成员】

    泛型类的静态成员需要特别关注。泛型类的静态成员只能在类的一个实例中共享。

  •     

     public class StaticDemo<T>
    {
    public static int x;
    } //由于同时对一个string类型和一个int 类型使用了 StaticDemo<T> 类。所以存在两组静态字段。
    StaticDemo<string>.x=;
    StaticDemo<int>.x=;
    Console.WriteLine(StaticDemo<string>.x);//

2、泛型接口

  【协变和抗变】

    协变和抗变指对参数和返回值类型进行转换。

    在.NET 中,参数类型是协变的。假定有 Shape 和 Rectangle 类,Rectangle 派生自Shape基类。声明 Display()方法是为了接受Shape 类型的对象作为其参数:    

public void Display(Shape o){ }

    方法的返回类型是抗变的。当方法返回一个Shape 时,不能把它赋予 Rectangle, 因为Shape不一定总是Rectangle。反过来是可行的:如果一个方法像 GetRectangle() 方法那样返回一个Rectangle,

public Rectangle GetRectangle();

就可以把结果赋予某个Shape

Shape s=GetRectangle();

在 .NET Framework4 版本之前,这种行为方式不适用于泛型。 在C# 4 中,扩展后的语言支持泛型接口和泛型委托的协变和抗变。

  泛型接口的协变

  如果泛型类型用 out 关键字标注,泛型接口就是协变的。这也意味着返回类型只能是 T 。 接口 IIndex 与 类型 T 是协变的,并从一个只读索引器中返回这个类型。

public interface IIndex<out T>
{
T this[int index] { get;}
int Count{get;}
}

C#高级编程笔记 Day 6, 2016年9月 14日 (泛型)的更多相关文章

  1. 2016年12月14日 星期三 --出埃及记 Exodus 21:9

    2016年12月14日 星期三 --出埃及记 Exodus 21:9 If he selects her for his son, he must grant her the rights of a ...

  2. 2016年11月14日 星期一 --出埃及记 Exodus 20:5

    2016年11月14日 星期一 --出埃及记 Exodus 20:5 You shall not bow down to them or worship them; for I, the LORD y ...

  3. 2016年10月14日 星期五 --出埃及记 Exodus 18:25

    2016年10月14日 星期五 --出埃及记 Exodus 18:25 He chose capable men from all Israel and made them leaders of th ...

  4. 关于苹果开发证书失效的解决方式(2016年2月14日Failed to locate or generate matching signing assets)

    前言: 从2月14日開始,上传程序的同学可能会遇到提示上传失败的提示. 而且打开自己的钥匙串,发现所有的证书所有都显示此证书签发者无效. Failed to locate or generate ma ...

  5. 2016年11月14日--SQL创建数据库、表-查、插、删、改

    --创建数据库(create database 数据库名)create database hq20161114go --使用选择数据库(use 数据库名)use hq20161114go --创建学生 ...

  6. Android高级编程笔记(四)深入探讨Activity(转)

    在应用程序中至少包含一个用来处理应用程序的主UI功能的主界面屏幕.这个主界面一般由多个Fragment组成,并由一组次要Activity支持.要在屏幕之间切换,就必须要启动一个新的Activity.一 ...

  7. 我的Python成长之路---第八天---Python基础(24)---2016年3月5日(晴)

    多线程编程 什么是多线程,线程是操作系统能够进行运算调度的最小单位.他包含在进程之中,是进程中的实际运作单位.线程是进程中一个单顺序的空值六,一个进程可以并发多个线程,每个线程可以并行处理不同的任务. ...

  8. 我的Python成长之路---第七天---Python基础(22)---2016年2月27日(晴)

    socket网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...

  9. 2016年2月16日开始,每天一篇,记录学习心得,【基本技能篇】>>开篇《如何阅读一本书——心得》

    如何阅读一本书——心得 ——2016年2月12日 要达到阅读的所有目的,就必须在阅读不同书籍的时候,运用适当的不同速度.读的太快或太慢,都一无所获. 四个阅读层次:①基础阅读,具有基本阅读的能力,包括 ...

随机推荐

  1. pycharm的使用破解和Anaconda的使用

    1.pycharm的破解: 版本: pycharm 2016.2.3 链接: 下载专业版本   下面是这个版本的注册码: 43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QTcz ...

  2. AR(增强现实) 知识篇

    增强现实(Augmented Reality,简称AR),是一种实时地计算摄影机影像的位置及角度并加上相应图像的技术,这种技术的目标是在屏幕上把虚拟世界套在现实世界并进行互动.这种技术估计由1990年 ...

  3. thinkphp

    U方法: 模板导入后,先在浏览器执行index.php文件,当出现下图时,框架中的内容才可以出现. 增加admin后台文件夹: 连接数据库:可以使用pdo的方式连接

  4. iis

    IIS架构 1.   概述 为了提高IIS的可靠性,安全性以及可用性,与IIS5.0和以前更早的版本不同,IIS6.0提供了一个全新的IIS架构.这个架构的详细情况如下图所示:             ...

  5. jquery修改css样式,样式带!important

    由于需求的需要,今天在用jquery修改一个弹出框的样式的时候,由于有一个按钮有padding-left:12px;导致内间距空出来的这一块颜色用普通的方式无法改变. 普通的jquery修改css的方 ...

  6. 【分享】国外后台界面HTML源码 [免费]

    国外后台界面HTML模版下载,里面的文字是英文的,不过可以修改成中文,带有数据统计界面和曲线图,本套模板相对完整,在主界面上点击那些菜单,都可以点开二级页面,希望对搞代码的程序员,对不擅长美工的朋友提 ...

  7. node.js的安装环境搭建

    .header { cursor: pointer } p { margin: 3px 6px } th { background: lightblue; width: 20% } table { t ...

  8. Fluent Nhibernate之旅(五)--利用AutoMapping进行简单开发

    Fluent Nhibernate(以下简称FN)发展到如今,已经相当成熟了,在Nhibernate的书中也相应的推荐了使用FN来进行映射配置,之前写的FN之旅至今还有很多人会来私信我问题,说来惭愧, ...

  9. java学习指南

    @Override public BaseResponse selectListPage(PageData page, Object obj) { BaseResponse response = ne ...

  10. windows下使用vs进行Proctocol Buffer开发(C++篇)

    因工作原因接触Proctocol Buffer(protobuf),至于什么是protobuf,为何使用protobuf,我就不赘述了,百度下都是答案. 今天我介绍的是在windows下使用vs进行p ...