C# 泛型应用的好处是什么呢?.NET 中的泛型使您可以重用代码以及在实现它时付出的努力。类型和内部数据可以在不导致代码膨胀的情况下更改,而不管您使用的是值类型还是引用类型。您可以一次性地开发、测试和部署代码,通过任何类型(包括将来的类型)来重用它,并且全部具有编译器支持和类型安全。因为一般代码不会强行对值类型进行装箱和取消装箱,或者对引用类型进行向下强制类型转换,所以性能得到显著提高。对于值类型,性能通常会提高 200%;对于引用类型,在访问该类型时,可以预期性能最多提高 100%(当然,整个应用程序的性能可能会提高,也可能不会提高)。本文随附的源代码包含一个微型基准应用程序,它在紧密循环中执行堆栈。该应用程序使您可以在基于 Object 的堆栈和一般堆栈上试验值类型和引用类型,以及更改循环迭代的次数以查看泛型对性能产生的影响。
C# 泛型应用分析
因为 IL 和 CLR 为泛型提供本机支持,所以大多数符合 CLR 的语言都可以利用一般类型。例如,下面这段 Visual Basic .NET 代码使用代码块 2 的一般堆栈:
Dim stack As Stack(Of Integer)
stack = new Stack(Of Integer)
stack.Push(3)
Dim number As Integer
number = stack.Pop()
- 1.
- 2.
- 3.
- 4.
- 5.
您可以在类和结构中使用泛型。以下是一个有用的一般点结构:
public struct Point
{
public T X;
public T Y;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
可以使用该一般点来表示整数坐标,例如:
Point point;
point.X = 1;
point.Y = 2;
- 1.
- 2.
- 3.
或者,可以使用它来表示要求浮点精度的图表坐标:
Point point;
point.X = 1.2;
point.Y = 3.4;
- 1.
- 2.
- 3.
除了到目前为止介绍的基本泛型语法以外,C# 2.0 还具有一些泛型特定的语法。例如,请考虑代码块 2 的 Pop() 方法。假设您不希望在堆栈为空时引发异常,而是希望返回堆栈中存储的类型的默认值。如果您使用基于 Object 的堆栈,则可以简单地返回 null,但是您还可以通过值类型来使用一般堆栈。为了解决该问题,您可以使用 default() 运算符,它返回类型的默认值。
下面说明如何在 Pop() 方法的实现中使用默认值:
public T Pop()
{
m_StackPointer--;
if(m_StackPointer >= 0)
{
return m_Items[m_StackPointer];
}
else
{
m_StackPointer = 0;
return default(T);
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
引用类型的默认值为 null,而值类型(例如,整型、枚举和结构)的默认值为全零(用零填充相应的结构)。因此,如果堆栈是用字符串构建的,则 Pop() 方法在堆栈为空时返回 null;如果堆栈是用整数构建的,则 Pop() 方法在堆栈为空时返回零。
C# 泛型应用之多个一般类型
单个类型可以定义多个一般类型参数。例如,请考虑代码块 3 中显示的一般链表。
C# 泛型应用代码块之一般链表
class Node
{
public K Key;
public T Item;
public Node NextNode;
public Node()
{
Key = default(K);
Item = defualt(T);
NextNode = null;
}
public Node(K key,T item,Node nextNode)
{
Key = key;
Item = item;
NextNode = nextNode;
}
}
public class LinkedList
{
Node m_Head;
public LinkedList()
{
m_Head = new Node();
}
public void AddHead(K key,T item)
{
Node newNode = new Node(key,item,m_Head.NextNode);
m_Head.NextNode = newNode;
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
该链表存储节点:
class Node
{...}
- 1.
- 2.
每个节点都包含一个键(属于一般类型参数 K)和一个值(属于一般类型参数 T)。每个节点还具有对该列表中下一个节点的引用。链表本身根据一般类型参数 K 和 T 进行定义:
public class LinkedList
{...}
- 1.
- 2.
这使该列表可以公开像 AddHead() 一样的一般方法:
public void AddHead(K key,T item);
- 1.
每当您声明使用泛型的类型的变量时,都必须指定要使用的类型。但是,指定的类型实参本身可以为一般类型参数。例如,该链表具有一个名为 m_Head 的 Node 类型的成员变量,用于引用该列表中的第一个项。m_Head 是使用该列表自己的一般类型参数 K 和 T 声明的。
Node m_Head;
- 1.
您需要在实例化节点时提供类型实参;同样,您可以使用该链表自己的一般类型参数:
public void AddHead(K key,T item)
{
Node newNode = new Node<K,T>(key,item,m_Head.NextNode);
m_Head.NextNode = newNode;
}
- 1.
- 2.
- 3.
- 4.
- 5.
请注意,该列表使用与节点相同的名称来表示一般类型参数完全是为了提高可读性;它也可以使用其他名称,例如:
public class LinkedList
{...}
- 1.
- 2.
或:
public class LinkedList
{...}
- 1.
- 2.
在这种情况下,将 m_Head 声明为:
Node m_Head;
- 1.
当客户端使用该链表时,该客户端必须提供类型实参。该客户端可以选择整数作为键,并且选择字符串作为数据项:
LinkedList list = new LinkedList();
list.AddHead(123,"AAA");
- 1.
- 2.
但是,该客户端可以选择其他任何组合(例如,时间戳)来表示键:
LinkedList list = new LinkedList();
list.AddHead(DateTime.Now,"AAA");
- 1.
- 2.
有时,为特定类型的特殊组合起别名是有用的。可以通过 using 语句完成该操作,如代码块 4 中所示。请注意,别名的作用范围是文件的作用范围,因此您必须按照与使用 using 命名空间相同的方式,在项目文件中反复起别名。
C# 泛型应用代码块之 一般类型别名
using List = LinkedList;
class ListClient
{
static void Main(string[] args)
{
List list = new List();
list.AddHead(123,"AAA");
}
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
C# 泛型应用及C# 泛型应用的优点就向你介绍到这里,希望对你了解和学习C# 泛型应用有所帮助。
【编辑推荐】