C#编程(二十八)----------泛型类的功能
泛型类的功能
在创建泛型类时,还需要一些其他的C#关键字.例如,不能把null赋予泛型类型.此时,可以使用default关键字.如果泛型类型不需要object类的功能,但需要调用泛型类上的某些特定方法,就可以定义约束.
例如:
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 > 0;
}
}
}
这是一个使用泛型文档福安里的实例.文档管理器用于从队列中读取文档.先创建一个新的控制台项目DocumentManager,并添加DocumentManager<T>类.AddDocument()方法将一个文档添加到队列中.如果队列不为空,IsDocumentAvailable只读属性就返回true.
默认值
接下来给DocumentManager<T>类添加衣蛾GetDocument()方法.
public T GetDocument()
{
T doc = default(T);
lock (this)
{
doc = documentQueue.Dequeue();
}
return doc;
}
在这个方法中,应该把类型T指定为null.但是不能把null赋予泛型类型.隐隐是泛型类型也可以实例化为值类型,而null只能用于引用类型.为了解决这个问题,使用了default关键字,通过default关键字,将null赋予引用类型,将0赋予值类型.
default关键字根据上下文可以有多重含义.switch语句使用default定义默认情况,在泛型中,根据泛型类型是引用类型还是值类型,泛型default用于将泛型类型初始化为null或0.
约束
如果泛型类型需要调用泛型类型中的方法,就必须加以约束.对于DocumentManager<T>,文档的所在标题应在DisplayAllDocuments()方法显示.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 { get; set; }
}
要使用DocumentManager<T>类显示文档,可以将类型T强制转换为IDocument接口,以显示标题:
public void DisplayAllDocument()
{
foreach (T doc in documentQueue)
{
Console.WriteLine(((IDocument)doc).Title);
}
}
问题是,如果类型T没有实现IDocument接口,这个类型强制转换就会导致一个运行异常.最好给DocumentManager<TDocument>类定义一个约束:TDocument类型必须实现IDocument接口.为了在反省类型的名称中指定该要求,将T改为TDocument.where子句指定了实现IDocument接口的要求.
public class DocumentManager<TDocument>
where TDocument : IDocument
{}
这样就可以编写foreach语句,从而使类型TDocument包含属性TItle. Visual Studio InterlliSense和编译器都会提供这个支持.
public void DisplayAllDocument()
{
foreach (TDocument doc in documentQueue)
{
Console.WriteLine(doc.Title);
}
}
在main()方法中,用Document类型实例化Documentmanager
<T>类,而Document类型实现了需要IDocument接口.接着添加和显示新文档,检索其中一个文档:
static void Main()
{
var dm= new Documentmanager<Document>();
dm.AddDocument(new Document(“Title A”,”Sample A”));
dm.AddDocument(new Document(“Title B”,”Sample B”));
dm.DisplayAllDocument();
if (dm.IsDocumentAvailable)
{
Document d=dm.GetDocument();
Console.WriteLine(d.Content);
}
}
DocumentManager现在可以处理任何实现了IDocument接口的类.
在示例应用程序中,介绍了接口约束.泛型支持集中约束类型,如下表:
约束 |
说明 |
where T :struct |
对于结构约束,类型T必须是值类型 |
where T:class |
类约束制定类型T必须是引用类型 |
where T:IFoo |
制定类型T必须实现接口IFoo |
whereT:Foo |
制定类型T必须派生自基类Foo |
whereT:new() |
这是一个构造函数约束,制定类型T必须有一个默认构造函数 |
where T:T2 |
这个约束也可以指定,类型T1派生自泛型类型T2.该约束也称为裸约束 |
只有为默认构造函数定义构造函数约束,不能为其他构造函数定义构造函数约束.
使用泛型类型还可以合并多个约束.where T:IFoo,new()约束和MyClass<T>声明指定,类型T必须实现IFoo接口,且必须有一个默认构造函数.
public class MyClass<T>
where T:IFoo,new()
{
//..
}
在C#中,where子句的一个重要限制是,不能定义必须由泛型类型实现的运算符.运算符不鞥在接口中定义.在where子句中,只能定义基类,接口和默认构造函数.
以上案例的完整代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication9
{
class Program
{
static void Main(string[] args)
{
var dm = new DocumentManager<Document>();
dm.AddDocument(new Document("Title A", "Sample A"));
dm.AddDocument(new Document("Title B", "Sample B"));
dm.DisplayAllDocument();
if (dm.IsDocumentAvailable)
{
Document d = dm.GetDocument();
Console.WriteLine(d.Content);
}
Console.ReadKey();
}
}
public class DocumentManager<TDocument>
where TDocument : IDocument
{
private readonly Queue<TDocument> documentQueue = new Queue<TDocument>();
public void AddDocument(TDocument doc)
{
lock (this)
{
documentQueue.Enqueue(doc);
}
}
public bool IsDocumentAvailable
{
get
{
return documentQueue.Count > 0;
}
}
public TDocument GetDocument()
{
TDocument doc = default(TDocument);
lock (this)
{
doc = documentQueue.Dequeue();
}
return doc;
}
public void DisplayAllDocument()
{
foreach (TDocument doc in documentQueue)
{
Console.WriteLine(doc.Title);
}
}
}
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 { get; set; }
}
}
继承
前面创建的LinkedList<T>类实现了IEnumerable<out T>接口:
public class LinkedList<T>:IEnumerable<out T>
{
//...
}
泛型类型可以实现泛型接口,也可以派生自一个类.泛型类还可以派生自泛型基类:
public class Base<T>
{
}
public class Derived<T>:Base<T>
{}
要求是必须重复接口的泛型类型,或者必须制定基类的类型,如:
public class Base<T>
{
}
public class Derived<T>:Base<string>
{}
于是,派生类可以是泛型类或者非泛型类.例如,可以定义一个抽象的泛型基类,它在派生类中用一个具体的类型实现.这允许对特定类型执行特殊的操作:
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;
}
}
静态成员
泛型类的静态成员需要特别关注.泛型类的景天成员只能在类的一个实例中共享.看下例,其中StaticDemo<T>类包含静态字段x:
public class StaticDemo<T>
{
public static int x;
}
在Main()函数中的代码如下:
static void Main(string[] args)
{
StaticDemo<string>.x = 4;
StaticDemo<int>.x = 5;
Console.WriteLine(StaticDemo<string>.x);
Console.ReadKey();
}
由于同时对一个string类型和一个int类型使用了StaticDemo<T>类,所以存在两组静态类型.
C#编程(二十八)----------泛型类的功能的更多相关文章
- (NO.00001)iOS游戏SpeedBoy Lite成形记(二十八):增加排行榜功能
游戏大体上基本也就完成了,还差一个排行榜.否则如何激励各位选手创造新纪录呢? 排行榜功能也没什么难的,不过需要一点点排序的算法上的考虑. 这里我们把排行榜记录数据和排序都放在GameState类中,在 ...
- Android开发(二十八)——基础功能函数
/** * 判断事件是否在控件中 * * @param view * @param ev * @return * @see http://m.blog.csdn.net/blog/aygxylxk/8 ...
- Web 前端开发人员和设计师必读文章推荐【系列二十八】
<Web 前端开发精华文章推荐>2014年第7期(总第28期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...
- VMware vSphere 服务器虚拟化之二十八 桌面虚拟化之安装View传输服务器
VMware vSphere 服务器虚拟化之二十八 桌面虚拟化之安装View传输服务器 View 传输服务器用于管理和简化数据中心与在最终用户本地系统上检出使用的 View 桌面之间的数据传输.必须安 ...
- (转载)Android项目实战(二十八):Zxing二维码实现及优化
Android项目实战(二十八):Zxing二维码实现及优化 前言: 多年之前接触过zxing实现二维码,没想到今日项目中再此使用竟然使用的还是zxing,百度之,竟是如此牛的玩意. 当然,项目中 ...
- (转载)Android项目实战(二十八):使用Zxing实现二维码及优化实例
Android项目实战(二十八):使用Zxing实现二维码及优化实例 作者:听着music睡 字体:[增加 减小] 类型:转载 时间:2016-11-21我要评论 这篇文章主要介绍了Android项目 ...
- 剑指Offer(二十八):数组中出现次数超过一半的数字
剑指Offer(二十八):数组中出现次数超过一半的数字 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn. ...
- 使用Typescript重构axios(十八)——请求取消功能:总体思路
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 使用Typescript重构axios(二十八)——自定义序列化请求参数
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- Bootstrap <基础二十八>列表组
列表组.列表组件用于以列表形式呈现复杂的和自定义的内容.创建一个基本的列表组的步骤如下: 向元素 <ul> 添加 class .list-group. 向 <li> 添加 cl ...
随机推荐
- javaweb笔记五
JSP:java server page服务器脚本语言.(脚本===插件),是一种在html代码中,嵌入java代码的方式.解决servlet产生动态页面缺陷而产生的一门技术.js:客户端脚本语言js ...
- Android Studio 入门级教程(二):新建一个属于自己的工程并安装Genymotion模拟器
声明 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4392611.html [系列] Andr ...
- 【LOJ】#6434. 「PKUSC2018」主斗地
题解 什么,我这题竟然快到了LOJ rk1???? 搜起来有点麻烦,不过感觉还是比斗地主好下手(至今没敢写斗地主 首先是暴力搜牌型,最多\(3^{16}\)(什么判解还要复杂度怂成一团)的样子?? 然 ...
- 【LOJ】#2513. 「BJOI2018」治疗之雨
题解 具体就是列一个未知数方程\(dp[i]\)表示有\(i\)滴血的时候期望多少轮 \(dp[i] = 1 + \sum_{j = 1}^{i + 1} a_{i,j}dp[j]\) \(dp[n] ...
- 发送统计邮件shell脚本
#!/bin/bash#作者:Presley#时间:2018.07.16#监控阿里云aaa库的py_weixin_product_close_rating_info 和 py_weixin_produ ...
- Java基础常见英语词汇(共70个)
——————————ASP.Net+Android+IOS开发..Net培训.期待与您交流!—————————— Java英文单词 OO: object—oriented ,面向对象 OOP:obje ...
- auth.User.groups: (fields.E304)
配置用户信息的models时,如果继承Abstractuser类时,报错: ERRORS:auth.User.groups: (fields.E304) Reverse accessor for 'U ...
- [转]我的数据结构不可能这么可爱!——珂朵莉树(ODT)详解
参考资料: Chtholly Tree (珂朵莉树) (应某毒瘤要求,删除链接,需要者自行去Bilibili搜索) 毒瘤数据结构之珂朵莉树 在全是珂学家的珂谷,你却不知道珂朵莉树?来跟诗乃一起学习珂朵 ...
- 循序渐进学.Net Core Web Api开发系列【1】:开发环境
系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.本篇概述 本篇不 ...
- 减少Building 'Xxx' Gradle project info等待时间
转载请注明出处:http://www.cnblogs.com/cnwutianhao/p/6640279.html 从Github上看到好的Demo想要Download下来学习.导入到Android ...