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);            }

使用泛型不仅避免了不要要的装箱和拆箱,还避免了类型检查。

代码重用,可扩展性

这里不做介绍

泛型链表

非泛型链表的实现

  1. 第一步(创建链表节点类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;        }    }
  1. 第二步(创建链表类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;            }        }    }
  1. 完整代码
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; }    }}

约束还有如下,如有多种约束,逗号隔开

约束 说明 where T:struct T类型必须是值类型 where T:class T类型必须是引用类型 where T:IFoo T类型必须实现IFoo接口 where T:Foo T类型必须继承Foo基类 where T:new() T类型必须有默认构造函数 where T:T2 T类型必须派生与泛型类型T2

继承

需要注意两点: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;    }

这里的演示说明,静态成员只作用于相同的数据类型,这里为两组静态成员

0 0
原创粉丝点击