------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------
泛型引例ArrayList
相信大家在看杨中科老师基础视频中都不陌生个类ArrayList,我的基础测试中也有关于这个类运用的一道题。可见泛型是很基础同时又是很重要的一个知识点。ArrayList通用化是通过在类型与通用基类型Object之间进行强制转换来实现的:添加到ArrayList中的任何引用或值类型都将隐式地向上强制转换为Object;如果项是值类型,则添加时需要进行装箱操作,检索时需要进行拆箱操作。
ArrayList通用化有2个主要缺点:强制转换以及装箱和拆箱操作都会降低性能(特别是大型集合时);另一个限制是缺少编译时类型检查,因为所有项都强制转换为Object,所以在编译时无法防止客户端代码执行非法操作。
using System;
using System.Collections;
namespace CSharpPractice.ArrayList
{
public class ArrayListTest
{
public static void Main()
{
//创建整型数组列表
ArrayList list1 = new ArrayList();
list1.Add(3);
list1.Add(105);
//显示整型数组列表中的值
Console.WriteLine("整型数组列表ArrayList1的内容如下:");
foreach (int x in list1)
{
Console.WriteLine(x);
}
//创建字符串型数组列表
ArrayList list2 = new ArrayList();
list2.Add("Hello");
list2.Add("Friends");
//显示字符串型数组列表中的值
Console.WriteLine("字符串型数组列表ArrayList2的内容如下:");
foreach (string s in list2)
{
Console.WriteLine(s);
}
//创建整数、字符串混合型数组列表
ArrayList list3 = new ArrayList();
list3.Add(11); // 添加一个整数.
list3.Add("字符串"); // 添加一个字符串
int t = 0;
// 求数组列表ArrayList3各元素之和
Console.WriteLine("数组列表ArrayList3各元素之和为:");
foreach (int x in list3) // 产生运行时错误:InvalidCastException
{
t += x;
}
Console.ReadLine();
}
}
}
引例List<T>
与ArrayList相比,使用 List<T>时,必须为每个实例指定其具体的数据类型。这样将不再需要向上强制转换为System.Object以及装箱和拆箱操作,同时也使得编译器可以进行类型检查,从而解决了ArrayList通用化的2个主要问题,保证了程序的性能和健壮性。
using System;
using System.Collections;
using System.Collections.Generic;
namespace CSharpPractice.ListT
{
public class ListTest
{
public static void Main()
{
//创建整型数组列表
List<int> list1 = new List<int>();
list1.Add(3);
list1.Add(105);
//显示整型数组列表中的值
Console.WriteLine("整型数组列表ArrayList1的内容如下:");
foreach (int x in list1)
{
Console.WriteLine(x);
}
//创建字符串型数组列表
List<string> list2 = new List<string>();
list2.Add("Hello");
list2.Add("Friends");
//显示字符串型数组列表中的值
Console.WriteLine("字符串型数组列表ArrayList2的内容如下:");
foreach (string s in list2)
{
Console.WriteLine(s);
}
// 试图创建整数、字符串混合型数组列表,失败!
List<int> list3 = new List<int>();
list3.Add(11); // 添加一个整数.
//list3.Add("字符串"); // 编译错误
list3.Add(22); // 添加另一个整数.
int t = 0;
Console.WriteLine("数组列表ArrayList3各元素之和为:");
foreach (int x in list3)
{
t += x;
}
Console.WriteLine(t);
Console.ReadLine();
}
}
}
一、泛型的概念与定义
泛型类似于 C++ 模板,通过泛型可以定义类型安全的数据结构,而无须使用实际的数据类型。例如,通过定义泛型方法(static void Swap<T>(ref T lhs, ref T rhs)),可以重用数据处理算法,实现不同类型数据(例如int、double)的交换,而无需分别为int和double复制类型特定的代码(重载方法),从而显著提高性能并得到更高质量的代码。.NET Framework 2.0版类库提供一个新的命名空间 System.Collections.Generic,其中包含若干基于泛型的集合类。在泛型类的声明中,需要声明泛型参数,然后在泛型类的成员声明中,使用该泛型参数作为通用类型;而在创建泛型类的实例时,则需要与泛型参数对应的实际类型。
2.泛型类型参数
在泛型类型定义中,必须通过指定尖括号中的类型参数来声明类型。类型参数实际上并不是特定类型,而只是类型占位符。在创建泛型类型的实例时,必须指定尖括号中的类型(可以是编译器识别的任何类型)
例如:
GenericList<float> list1 = new GenericList<float>();
GenericList<ExampleClass> list2 = new GenericList<ExampleClass>();
GenericList<ExampleStruct> list3 = new GenericList<ExampleStruct>();
类型参数遵循下列命名准则
使用“T”作为描述性类型参数名的前缀,并使用描述性名称命名泛型类型参数。
using System;
using System.Collections.Generic;
namespace CSharpPractice.Generic
{
public class GenericList<T>
{
// 嵌套类也通过泛型参数(<T>)定义.
private class Node
{ // T用于非泛型构造函数.
public Node(T t)
{
next = null;
data = t;
}
private Node next;
public Node Next
{
get { return next; }
set { next = value; }
}
// T作为数据类型私有成员.
private T data;
// T作为属性返回类型.
public T Data
{
get { return data; }
set { data = value; }
}
}
private Node head;
public GenericList() // 构造函数
{ // 堆栈(后进先出)初始化
head = null;
}
// T作为方法的参数类型:
public void AddHead(T t)
{ // 新结点加入到当前堆栈的头部,并且成为head
Node n = new Node(t);
n.Next = head;
head = n;
}
public IEnumerator<T> GetEnumerator()
{ // 从头到尾依次输出堆栈中的值
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
}
class TestGenericList
{
static void Main()
{ // int是类型参数
GenericList<int> list = new GenericList<int>();
Console.WriteLine("0~9 十个整数形成堆栈");
for (int x = 0; x < 10; x++)
{ // 0~9 十个整数形成堆栈
list.AddHead(x);
}
Console.WriteLine("堆栈(后进先出)内容如下:");
foreach (int i in list)
{ // 输出堆栈内容9~0
Console.Write(i + " ");
}
Console.ReadLine();
}
}
}
二、泛型接口
在泛型类的设计中,通常也把泛型类共通要实现的方法、委托或事件的签名封装为泛型接口,然后在实现这些泛型接口的泛型类中实现这些方法等,下面是泛型接口示例。
using System;
using System.Collections.Generic;
namespace CSharpPractice.GenericInterface
{
class Program
{
static void Main()
{
int[] arr = { 0, 1, 2, 3, 4 };
List<int> list = new List<int>();
for (int x = 5; x < 10; x++)
{ // 形成列表 5、6、7、8、9
list.Add(x);
}
Console.WriteLine("输出数组列表ArrayList的内容:");
ProcessItems<int>(arr);
Console.WriteLine("输出列表List的内容:");
ProcessItems<int>(list);
Console.ReadLine();
}
static void ProcessItems<T>(IList<T> coll)
{
foreach (T item in coll)
{
Console.Write(item.ToString() + " ");
}
Console.WriteLine();
}
}
}
三、泛型方法
泛型方法是使用类型参数声明的方法。编译器能够根据传入的方法实参推断类型形参。
using System;
namespace CSharpPractice.GenericMethod
{
public class GenericMethod
{
//声明泛型方法:两者交换
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
public static void Main()
{
int a = 1;
int b = 2;
Console.WriteLine("Original value, a = {0} , b = {1}", a, b);
//调用泛型方法:指定泛型参数的类型
Swap<int>(ref a, ref b);
Console.WriteLine("After swapping, a = {0} , b = {1}", a, b);
//调用泛型方法:可以省略类型参数,编译器将推断出该参数
double c = 1.1d;
double d = 2.2d;
Console.WriteLine("Original value, c = {0} , d = {1}", c, d);
Swap(ref c, ref d);
Console.WriteLine("After swapping, c = {0} , d = {1}", c, d);
Console.ReadLine();
}
}
}
四、泛型委托和泛型事件
通过泛型类型参数,同样可以定义泛型委托。通过指定类型参数,可以引用泛型委托
在泛型类内部定义的委托,可以使用泛型类的泛型类型参数
基于泛型委托,可以定义泛型事件。此时发送方参数可以为强类型,不再需要强制转换成Object,或反向强制转换,下面给出泛型委托和事件示例。
using System;
namespace CSharpPractice.GenericIntegrated
{
// 类型参数T使用尖括号< >括起.
public class GenericList<T> : System.Collections.Generic.IEnumerable<T>
{
protected Node head;
protected Node current = null;
// 嵌套类也是关于T的泛型类
protected class Node
{
public Node next;
private T data; // T作为私有成员数据类型
public Node(T t) // T用于非泛化构造函数
{
next = null;
data = t;
}
public Node Next
{
get { return next; }
set { next = value; }
}
public T Data // T 作为属性的返回类型
{
get { return data; }
set { data = value; }
}
}
public GenericList() // 构造函数
{
head = null;
}
public void AddHead(T t) // T 作为成员参数类型
{ //新结点加入到当前列表的头部,并且成为head
Node n = new Node(t);
n.Next = head;
head = n;
}
// Implementation of the iterator
public System.Collections.Generic.IEnumerator<T> GetEnumerator()
{ // 从头到尾依次遍历列表中每个节点
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
// IEnumerable<T>继承自IEnumerable,所以该类必须同时实现
// GetEnumerator的泛型和非泛型方法。通常非泛型方法可以通过
// 直接调用泛型方法来简化实现过程
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class SortedList<T> : GenericList<T> where T : System.IComparable<T>
{
// 一个简单的、未经优化的排序算法:将列表元素从小到大排序
public void BubbleSort() // 冒泡排序
{
if (null == head || null == head.Next)
{
return;
}
bool swapped;
do
{
Node previous = null;
Node current = head;
swapped = false;
while (current.next != null)
{ // SortedList类在IEnumerable<T>上约束???
// Because we need to call this method, the SortedList
// class is constrained on IEnumerable<T>
if (current.Data.CompareTo(current.next.Data) > 0)
{
Node tmp = current.next;
current.next = current.next.next;
tmp.next = current;
if (previous == null)
{
head = tmp;
}
else
{
previous.next = tmp;
}
previous = tmp;
swapped = true;
}
else
{
previous = current;
current = current.next;
}
}
} while (swapped);
}
}
// 定义一个简单的类Person来实现IComparable<T> ,
// 类Person本身作为类型参数。
public class Person : System.IComparable<Person>
{
string name; // 姓名
int age; // 年龄
public Person(string s, int i)
{
name = s;
age = i;
}
// 对列表元素根据年龄排序.
public int CompareTo(Person p)
{
return age - p.age;
}
public override string ToString()
{
return name + ":" + age;
}
// 实现Equals方法,判断两个人是否同龄.
public bool Equals(Person p)
{
return (this.age == p.age);
}
}
class TestSortedList
{
static void Main()
{
// 声明和实例化一个新的泛型SortedList类.
// Person 作为类型参数.
SortedList<Person> list = new SortedList<Person>();
// 初始化Person对象,对name和age赋初值.
string[] names = new string[]
{
"刘一",
"陈二",
"张三",
"李四",
"王五",
"姚六",
};
int[] ages = new int[] { 45, 19, 28, 23, 18, 79 };
// 形成由name和age组成的列表.
for (int x = 0; x < 6; x++)
{
list.AddHead(new Person(names[x], ages[x]));
}
// 打印无序列表.
Console.WriteLine("初始(无序)列表为:");
foreach (Person p in list)
{
Console.Write(p.ToString() + " ");
}
Console.WriteLine();
// 列表排序.
list.BubbleSort();
// 打印有序列表.
Console.WriteLine("\n按年龄排好序的列表为:");
foreach (Person p in list)
{
Console.Write(p.ToString() + " ");
}
Console.ReadLine();
}
}
}
------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------