#集合与泛型
集合类:
–非泛型集合【System.Collections,System.Collections.Specialized】
–泛型集合【System.Collections.Generic】
##非泛型集合
ArrayList
BitArray
Hashtable
Queue
SortedList
Stack
HybridDictionary
ListDictionary
StringCollection
BitVector32
相关接口:
ICollection 为所有非泛型集合类型定义基本特性
ICloneable 为实现它的对象,向调用者返回对象的副本
IDictionary 允许非泛型集合对象使用名称/值对来表示其内容
IEnumerable
IEnumerator
IList
2.非泛型集合一般针对的对象类型是System.Object
装箱:把值类型数据保存在引用类型变量中。
static void SimpleBoxUnboxOperation()
{
int myInt = 25;
// 显式地将值类型分配给System.Object变量的过程
// 对值类型进行装箱时,CLR会在堆上分配新的对象并且将值类型的值复制到那个实例上。因此,返回给我们的就是新分配在堆上的对象的引用。
object boxedInt = myInt;
}
拆箱:把保存在对象引用中的值转换回栈上的相应值类型。
static void SimpleBoxUnboxOperation()
{
int myInt = 25;
object boxedInt = myInt;
// CLR会验证收到的值类型是不是等价于装箱的类型。
// 如果是,就将值复制回本地栈变量上。
// 如果不是,将抛出InvalidCastException异常。
int unboxedInt = (int)boxedInt;
}
在传递给需要object的方法时,值类型会自动装箱。
static void WorkWithArrayList()
{
ArrayList myInts = new ArrayList();
// 在传递给需要object的方法时,值类型会自动装箱
myInts.Add(10);
myInts.Add(20);
myInts.Add(35);
// 当将object转换回栈数据时,会发送拆箱
int i = (int)myInts[0];
Console.WriteLine("Value of your int:{0}", i);
}
装箱和拆箱时细节:
在托管堆上分配一个新对象
基于栈数据的值必须被转移到新分配的内存位置
在拆箱时,保存在堆对象中的值必须转移回栈
堆上无用的对象【最后】会被回收
##泛型集合
1.
与非泛型容器相比,泛型容器的一些优势
提供了更好的性能,因为没有装箱和拆箱过程
更类型安全,因为只包含我们指定的类型
大幅减少了构建自定义集合类型的需要
2.只有类,结构,接口,委托可以使用泛型,枚举类型不可以。
泛型的类型参数的名称可以随意取。但通常,T表示类型,TKey或K表示键,TValue或V表示值。
3.非泛型接口指定类型参数
// 非泛型版本
public interface IComparable
{
int CompareTo(object obj);
}
// 泛型版本
public interface IComparable<T>
{
int CompareTo(T obj);
}
public class Car : IComparable<Car>
{
...
// IComparable<T>的实现
int IComparable<Car>.CompareTo(Car obj)
{
if(this.CarID > obj.CarID)
return 1;
if(this.CarID < obj.CarID)
return -1;
else
return 0;
}
}
4.System.Collections.Generic
// 泛型接口
ICollection<T>
ICompare<T>
IDictionary<TKey, TValue>
IEnumerable<T>
IEnumerator<T>
IList<T>
ISet<T>
// 泛型类
Dictionary<TKey, TValue>
LinkedList<T>
List<T>
Queue<T>
SortedDictionary<TKey, TValue>
SortedSet<T>
Stack<T>
HashSet<T>
对象初始化语法。
集合初始化语法:
只能对支持Add()方法的类使用集合初始化语法。
// 初始化标准数组
int[] myArrayOfInts = {0, 1, 2, 3};
// 初始化int的泛型List<>
List<int> myGenericList = new List<int>{0, 1, 2, 3};
// 用数字数据初始化ArrayList
ArrayList myList = new ArrayList{0, 1, 2, 3};
// 综合使用对象初始化和集合初始化
List<Point> myListOfPoints = new List<Point>
{
new Point{X=2, Y=2},
new Point{X=3, Y=3},
new Point(PointColor.BloodRed){X=4, Y=4}
};
6.System.Collections.ObjectModel
ObservableCollection<T> 添加,移除项或刷新整个列表时提供通知的动态数据集合
ReadOnlyObservableCollection<T>
// ObservableCollection<T>实现了与List<T>相同的核心接口。不同的是,ObservableCollection<T>实现了一个名为CollectionChanged的事件。该事件将在插入新项,移除当前项或修改整个集合时触发。
// CollectionChanged定义为委托【这里为NotifyCollectionChangedEventHandler】
// 该委托可以调用任何以object为第一个参数,以NotifyCollectionChangedEventArgs为第二个参数的方法
class Program
{
static void Main()
{
ObservableCollection<Person> people = new ObservableCollection<Person>()
{
new Person{FirstName="Peter", LastName="Murphy", Age=52},
new Person{FirstName="Kevin", LastName="Key", Age=48},
};
people.CollectionChanged += people_CollectionChanged;
}
static void people_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
Console.WriteLine("Action for this event:{0}", e.Action);
if(e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
Console.WriteLine("Here are the OLD items:");
foreach (Person p in e.OldItems)
{
Console.WriteLine(p.ToString());
}
Console.WriteLine();
}
if(e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
Console.WriteLine("Here are the NEW items:");
foreach(Person p in e.NewItems)
{
Console.WriteLine(p.ToString());
}
}
}
}
7.自定义泛型方法
static void Swap<T>(ref T a, ref T b)
{
Console.WriteLine("You sent the Swap() method a {0}", typeof(T));
T temp;
temp = a;
a = b;
b = temp;
}
static void Main()
{
Console.WriteLine("******Fun with custom Generic Methods ******\n");
int a = 10, b = 90;
Console.WriteLine("Before swap:{0}, {1}", a, b);
Swap<int>(ref a, ref b);
Console.WriteLine("After swap:{0}, {1}", a, b);
Console.WriteLine();
string s1 = "Hello", s2 = "There";
Console.WriteLine("Before swap:{0} {1}", s1, s2);
Swap<string>(ref s1, ref s2);
Console.WriteLine("After swap:{0} {1}", s1, s2);
Console.ReadLine();
}
当使用泛型时,不指定类型参数时,编译器会基于成员参数推断类型参数。
类型参数推断只在泛型方法至少有一个参数时起作用。
8.自定义泛型结构和类
public struct Point<T>
{
private T xPos;
private T yPos;
public Point(T xVal, T yVal)
{
xPos = xVal;
yPos = yVal;
}
public T X
{
get{return xPos;}
set{xPos = value;}
}
public T Y
{
get{return xPos;}
set{xPos = value;}
}
public override string ToString()
{
return string.Format("[{0},{1}]", xPos, yPos);
}
public void ResetPoint()
{
// default(类型参数) 返回一个类型参数的默认值
xPos = default(T);
yPos = default(T);
}
}
9.类型参数的约束
任何泛型项须至少有一个类型参数,并在与泛型类型或参数交互时指定该类型参数。
使用where可以对给定的类型参数添加一组约束。
where T : ???
???:
struct 类型参数T须在其继承链中包含System.ValueType值类型。
class 类型参数T不能在其继承链中包含System.ValueType值类型。
new() 类型参数T须包含一个默认的构造函数。【在有多个约束的类型上,此约束须列在末尾】
NameOfBaseClass 类型参数T须派生于NameOfBaseClass指定的类
NameOfInterface 类型参数T须实现NameOfInterface指定的接口
// 类型参数T为引用类型,且实现了IDrawable,且具备默认构造
// 要为多个类型参数指定多个约束集时,用多个where语句
// where也可以用在限制泛型方法中的类型参数
public class MyGenericClass<T> where T : class, IDrawable, new()
{
...
}
目前版本不支持对泛型的类型参数应用C#操作符