1. 概述
(1)泛型並不是一個全新的結構,其他語言中有類似的概念。例如,C++模板就與泛型相似。
1.1 性能
(1)對值類型使用非泛型集合類,在把值類型轉換爲引用類型,和把引用類型轉換爲值類型時,需要進行裝箱和拆箱操作。
(2)值類型存儲在棧上,引用類型存儲在堆上。C#類是引用類型,結構是值類。
(3)從值類型轉換爲引用類型稱爲裝箱。
1.2 類型安全
1.3 二進制代碼的重用
1.4 代碼的擴展
1.5 命名約定
- 泛型類型的名稱用字母T作爲前綴。
- 如果沒有特殊的要求,泛型類型允許用任意類替代,且只使用了一個泛型類型,就可以用字符T作爲泛型類型的名稱。
- 如果泛型類型有特定的要求(例如,它必須實現一個接口或派生自鞠,或者使用了兩個或多個泛型類型,就應給泛型類型使用描述性的名稱:
2. 創建泛型類
(1)一個一般的、非泛型的簡化鏈表類,在鏈表中,一個元素引用下一個元素
代碼:
namespace study5_2
{
//鏈表結點,包括前一個指針,後一個指針,以及當前值
public class LinkedListNode
{
public object Value { get; private set; }
public LinkedListNode Next { get; internal set; }
public LinkedListNode Prev { get; internal set; }
public LinkedListNode(object value)
{
this.Value = value;
}
}
public class LinkedList:IEnumerable
{
public LinkedListNode First { get; private set; }//鏈表
public LinkedListNode Last { get; private set; }//鏈尾
public LinkedListNode AddLast(object node)
{
var newNode = new LinkedListNode(node);
if (First == null)
{
First = newNode;
newNode.Prev = Last;
Last = First;
}
else
{
LinkedListNode previous = Last;
Last.Next = newNode;
Last = newNode;
Last.Prev = previous;
}
return newNode;
}
public IEnumerator GetEnumerator()
{
LinkedListNode current = First;
while(current!=null)
{
yield return current.Value;
current = current.Next;
}
}
}
class Program
{
static void Main(string[] args)
{
var list1 = new LinkedList();
list1.AddLast(2);
list1.AddLast(4);
list1.AddLast("6");
foreach (int i in list1)
{
Console.WriteLine(i);
}
}
}
}
結果:
(2)鏈表的泛型版本:
代碼:
namespace study5_2
{
//鏈表結點,包括前一個指針,後一個指針,以及當前值
public class LinkedListNode<T>
{
public T Value { get; private set; }
public LinkedListNode<T> Next { get; internal set; }
public LinkedListNode<T> Prev { get; internal set; }
public LinkedListNode(T value)
{
this.Value = value;
}
}
public class LinkedList<T>:IEnumerable<T>
{
public LinkedListNode<T> First { get; private set; }//鏈表
public LinkedListNode<T> Last { get; private set; }//鏈尾
public LinkedListNode<T> AddLast(T node)
{
var newNode = new LinkedListNode<T>(node);
if (First == null)
{
First = newNode;
newNode.Prev = Last;
Last = First;
}
else
{
LinkedListNode<T> previous = Last;
Last.Next = newNode;
Last = newNode;
Last.Prev = previous;
}
return newNode;
}
public IEnumerator<T> GetEnumerator()
{
LinkedListNode<T> current = First;
while(current!=null)
{
yield return current.Value;
current = current.Next;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class Program
{
static void Main(string[] args)
{
var list1 = new LinkedList<int>();
list1.AddLast(2);
list1.AddLast(4);
list1.AddLast(6);
foreach (int i in list1)
{
Console.WriteLine(i);
}
}
}
}
結果:
3. 泛型類的功能
(1)代碼
namespace study5_3
{
public interface IDocument
{
string Title { get; set; }
string Content { get; set; }
}
public class Document:IDocument
{
public string Title { get; set; }
public string Content { get; set; }
public Document()
{
}
public Document(string title, string content)
{
this.Title = title;
this.Content = content;
}
}
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; }
}
public T GetDocument()
{
T doc = default(T);
lock(this)
{
doc = documentQueue.Dequeue();
}
return doc;
}
public void DisplayAllDocuments()
{
foreach(T doc in documentQueue)
{
Console.WriteLine(((IDocument)doc).Title);
}
}
}
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.DisplayAllDocuments();
if(dm.IsDocumentAvailable)
{
Document d = dm.GetDocument();
Console.WriteLine(d.Content);
}
}
}
}
(2)結果
3.1 默認值
(1)現在給DocumentManager<T>添加一個GetDocument()方法。在這個方法中,應把類型T指定爲null。但是,不能把null 賦予泛型類型。原因是泛型類型也可以實例化爲值類型,而null只能用於引用類型。爲了解決這個問題,可以使用default關鍵字。通過default關鍵字,將null賦予引用類型,將0賦予值類型。
3.2 約束
(1)泛型支持幾種約束類型
3.3 繼承
(1)泛型類型可以實現泛型接口,也可以派生自一個類。泛型類可以派生自泛型基類:
public class Base<T>
{
}
public class Derived<T> : Base<T>
{
}
3.4 靜態成員
(1)泛型類的靜態成員只能在類的一個實例中共享。下面StaticDemo<T>類包含靜態字段x:
public class StaticDemo<T>
{
public static int x;
}
4. 泛型接口
(1)使用泛型可以定義接口,在按口中定義的方法可以帶泛型參數。
4.1 協變和抗變
(1).NET4通過協變和抗變爲泛型接口和泛型委託添加了一個重要的擴展。協變和抗變指對參數和返回值的類型進行轉換。
4.2 泛型接口的協變
(1)如果泛型類型用out關鍵字標註,泛型接口就是協變的。這也意味着返回類型只能是T。
public interface IIndex<out T>
{
T this[int index] { get; }
int Count { get; }
}
4.3 泛型接口的抗變
PS:對泛型結構瞭解還不深,希望大家能夠幫助我多瞭解瞭解,謝謝。
小結:
(1)泛型類似於一個模板。在把值類型轉換爲引用類型,和把引用類型轉換爲值類型時,需要進行裝箱和拆箱操作。
(2)代碼1:
namespace restudy5_1_2
{
class Program
{
static void Main(string[] args)
{
var list = new ArrayList();
list.Add(123);
list.Add("aaa");
list.Add("monb");
foreach (var i in list)
{
Console.WriteLine(i);
}
}
}
}