C# 泛型
来源:互联网 发布:笔记本摄像头录像软件 编辑:程序博客网 时间:2024/05/17 09:01
泛型的概念
什么是泛型?
泛型类似于C++中的模板,是C#语言的一部分,与IL紧密集成。与C++模板不同的是,C++使用模板时必须要模板源码。泛型可以创建与独立被包含的类和方法,不需要为每种类型编写不同的类或方法。
泛型的优点
性能
var list = new ArrayList();list.Add(10);int l1 = (int)list[0];
这里首先list.Add方法经过一次装箱。在取list元素时又经过一次强制转换(拆箱)操作,装箱和拆箱都会对性能有所损失。
安全
var list = new ArrayList(); list.Add(10); list.Add("20"); foreach (int item in list) { Console.WriteLine(item); }
由于没使用泛型,这里ArrayList可以随意放入任何类型数据,这对于类型安全方面是严重欠缺的。
List<int> list = new List<int>(); list.Add(10); list.Add(20); foreach (int item in list) { Console.WriteLine(item); }
使用泛型不仅避免了不要要的装箱和拆箱,还避免了类型检查。
代码重用,可扩展性
这里不做介绍
泛型链表
非泛型链表的实现
- 第一步(创建链表节点类LinkedListNode。)
class LinkedListNode { internal object Value{get;private set;} internal LinkedListNode Next { get; set; } internal LinkedListNode Previous { get; set; } public LinkedListNode(object value) { this.Value = value; } }
- 第二步(创建链表类LinkedList)
class LinkedList:IEnumerable { //第一步:创建三个属性,标识第一个节点,最后一个节点和当前链表总节点数.set设置私有化。 public LinkedListNode First { get;private set; } public LinkedListNode Last { get;private set; } public int Count { get;private set; } //第二步:实现添加节点方法 public LinkedListNode AddLast(object node) { //将参数包装成节点 var currentnode = new LinkedListNode(node); if (First == null) { First = currentnode; Last = currentnode; } else { Last.Next = currentnode; //最后一个节点的下一个节点为当前包装的节点 currentnode.Previous = Last;//当前包装节点的上一个节点为最后一个节点 Last = currentnode; //最后将新节点赋值给last } Count++; return currentnode; } //第三步:IEnumerable实现GetEnumerator方法,支持foreach public IEnumerator GetEnumerator() { LinkedListNode currentnode = First; while (currentnode!=null) { yield return currentnode.Value; currentnode = currentnode.Next; } } }
- 完整代码
using System;using System.Collections;using System.Linq;using System.Text;using System.Threading.Tasks;namespace ConsoleApplication23{ class Program { static void Main(string[] args) { LinkedList list = new LinkedList(); list.AddLast("Hello"); list.AddLast("World"); foreach (string item in list) { Console.WriteLine(item); } } } /// <summary> /// 链表类 /// </summary> class LinkedList:IEnumerable { //第一步:创建三个属性,标识第一个节点,最后一个节点和当前链表总节点数.set设置私有化。 public LinkedListNode First { get;private set; } public LinkedListNode Last { get;private set; } public int Count { get;private set; } //第二步:实现添加节点方法 public LinkedListNode AddLast(object node) { //将参数包装成节点 var currentnode = new LinkedListNode(node); if (First == null) { First = currentnode; Last = currentnode; } else { Last.Next = currentnode; //最后一个节点的下一个节点为当前包装的节点 currentnode.Previous = Last;//当前包装节点的上一个节点为最后一个节点 Last = currentnode; //最后将新节点赋值给last } Count++; return currentnode; } //第三步:IEnumerable实现GetEnumerator方法,支持foreach public IEnumerator GetEnumerator() { LinkedListNode currentnode = First; while (currentnode!=null) { yield return currentnode.Value; currentnode = currentnode.Next; } } } /// <summary> /// 链表节点类 /// </summary> class LinkedListNode { internal object Value{get;private set;} internal LinkedListNode Next { get; set; } internal LinkedListNode Previous { get; set; } public LinkedListNode(object value) { this.Value = value; } }}
此段代码并不具有泛型拥有的优点,如果将main方法中的foreach接受类型换成int,代码将会运行时错误。且执行AddLast方法时有不必要的装箱操作
泛型链表的实现
可以直接根据上续非泛型链表逻辑加以改造,为了印象深刻,最好重写一遍逻辑。
using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace ConsoleApplication23{ class Program { static void Main(string[] args) { LinkedList<string> list = new LinkedList<string>(); list.AddLast("Hello"); list.AddLast("World"); foreach (string item in list) { Console.WriteLine(item); } } } class LinkedList<T>:IEnumerable<T> { public LinkedListNode<T> Fisrt { get;private set; } public LinkedListNode<T> Last { get;private set; } public int Count { get; set; } public LinkedListNode<T> AddLast(T node) { LinkedListNode<T> newnode = new LinkedListNode<T>(node); if (Fisrt == null) { Fisrt = newnode; Last = newnode; } else { Last.Next = newnode; newnode.Previous = Last; Last = newnode; } Count++; return newnode; } public IEnumerator<T> GetEnumerator() { LinkedListNode<T> node = Fisrt; while (node != null) { yield return node.Value; node = node.Next; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } class LinkedListNode<T> { public T Value { get;private set; } public LinkedListNode<T> Next { get; internal set; } public LinkedListNode<T> Previous { get;internal set; } public LinkedListNode(T value) { this.Value = value; } }}
泛型类的功能
using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace ConsoleApplication23{ class Program { static void Main(string[] args) { DocumentManager<Document> doc = new DocumentManager<Document>(); doc.AddDocument(new Document() { Title = "title1", Content = "content1" }); doc.DisplayAllDocuments(); } } 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 DisplayAllDocuments() { foreach (TDocument doc in documentqueue) { Console.WriteLine(doc.Title + "-" + doc.Content); } } } 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; } }}
如上代码:
定义了一个泛型文档管理器,其中有AddDucment,GetDocument,DisplayAllDocuments方法。
定义了一个IDocument文档接口,两个属性,title和content
定义了一个文档类document,实现了idocument接口
默认值
文档管理器中,GetDocument方法,如果队列为空应当返回默认值,此时不确定T类型是值类型还是引用类型,不能纯粹的返回null或者0,因此用到default。
它将根据具体的数据类型初始化默认值。
约束
假设文档管理器没有where约束TDocument必须继承IDocument的话。那么我们在DisplayAllDocument方法中遍历显示时,应当将doc进行强制转换才能得到Title和Content属性。
但是因为没有约束,main方法中初始化文档管理器可以指定随意类型,因此在强制转换IDocment接口时将会抛出异常。
using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace ConsoleApplication23{ class Program { static void Main(string[] args) { //DocumentManager<Document> doc = new DocumentManager<Document>(); //doc.AddDocument(new Document() { Title = "title1", Content = "content1" }); //doc.DisplayAllDocuments(); DocumentManager<int> doc = new DocumentManager<int>(); doc.AddDocument(1); doc.DisplayAllDocuments(); } } 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 DisplayAllDocuments() { foreach (TDocument doc in documentqueue) { Console.WriteLine(((IDocument)doc).Title); //Console.WriteLine(doc.Title + "-" + doc.Content); } } } 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; } }}
约束还有如下,如有多种约束,逗号隔开
继承
需要注意两点:1.重复基类泛型的类型 2.知道基类的类型
public class Base<T> { }public class Derived<T> : Base<T> { }
public class Base<T> { } public class Derived<T> : Base<int> { }
静态成员
class Program { static void Main(string[] args) { Base<int>.i = 5; Base<string>.i = 10; Console.WriteLine(Base<int>.i);//5 Console.WriteLine(Base<string>.i);//10 } } public class Base<T> { public static int i; }
这里的演示说明,静态成员只作用于相同的数据类型,这里为两组静态成员
- C#泛型
- c#泛型
- C# 泛型
- C#泛型
- C# 泛型
- C#泛型
- C# 泛型
- C# 泛型
- C# 泛型
- c# 泛型
- C# 泛型
- C# 泛型
- C#泛型
- C# 泛型
- C# - 泛型
- C#泛型
- C#泛型
- C# 泛型
- MyBatis学习总结[1]-入门
- Linux 文件的access time、modify time、change time。
- JavaWeb开发入门知识准备
- 断点知识
- AndroidEventBus简单总结
- C# 泛型
- BZOJ1042——[HAOI2008]硬币购物
- rxjava小试牛刀
- JAVA-问题本
- 使用yum命令报错File "/usr/bin/yum", line 30 except KeyboardInterrupt, e:
- 对文件进行异或加解密的方法
- 每天一个linux命令(6):rmdir 命令
- Android 模拟表单上传 多图片上传
- jmeter https