数组合并了相同类型的对象,而元组合并了不同类型的对象.Net 4定义了 8个泛型 Tuple类 和一个静态 Tuple类 ,它们用作元组的工厂。 这里的不同泛型 Tuple类支持不同数量的元素。 例如,Tuple<T1> 包含-个元素,Ttple<T1,T2> 包含两个元素,以此类推,元组用Tuple的静态Create()方法创建。
1 public static Tuple<int, int> Divide(int dividend, int divisor) 2 { 3 int result = dividend / divisor; 4 int reminder = dividend % divisor; 5 return Tuple.Create(result, reminder); 6 } 7
8 var result = Divide(2,3); 9 Console.WriteLine("result if division:{0},reminder:{1}", result.Item1, result.Item2);
如果元组包含的项超过 8个,就可 以使用 带 8个参数的 Tuple类 定义。 最后一个模板参数是 TRrest,表示必须给它传递一个元组。 这样,就可以创建带任意个参数的元组了,可在类上右键转到定义查看。
大多数集合类都可在 systm.Collections和 system.Collections.Generic名称空间中找到 。 泛型集合 类 位 于System.Collections.Generic名 称 空 间 中,专门于特定类型的集合类位于System.Collections.Specialized名称空间中,线程安全的集合位于System.Collections.Concurrent名称空间中。
集合和列表实现的接口:
.Net Framework为动态列表提供了泛型类List<T>.这个类实现了IList,IConllection,IEnumerable IList<T>,ICollection<T>和IEnunerable<T>接口。
使用默认的构造函数创建一个空列表,元素添加到列表后,列表的容量就会扩大为可接纳4个元素,如果添加了第5个元素,列表的大小就会变为原来的2倍,以此类推。如果列表的容量改变了,整个集合就会重新分配到一个新的内存中,所以为了节省时间,如果事先知道列表的容量,就可以用构造函数定义其容量。
List<int> list = new List<int>() { 1, 2 }; list.Add(3);//添加 list.Insert(0, 4);//插入 for (int i = 0; i < list.Count; i++) { Console.WriteLine(list[i]);//访问元素 } list.RemoveAt(3);//删除 int num= list.IndexOf(2);//查找 list.Sort();//排序 foreach (var item in list) { Console.WriteLine(item); } list.AsReadOnly();//设置为只读集合,所有的修改集合的方法和属性都会抛出NotSupportedExection异常
2.3队列
队列是其元素 以先进先出的 方式来处理的集合。使用泛型类Queue<T>实现
Queue<T>类的方法:
栈是与队列非常相似的一个容器,但它是先进后出。
Statck<T>类的成员:
LinkList<T>是一个双向链表,其元素指向它前面和后面的元素。链表的优点是,如果将元素插入到列表的中间位置,使用链表会非常快,在插入一个元素时,只需修改上一个元素的 Next引 用和下一个元素的Previous引用 ,使 它们引用所插入的元素。缺点是链表元素只能一个接一个的访问。
如果需要基于键对所需集合排序,就可 以使用 SoftedList<TKey,TValue>类。这个类按照键给元素排序。 集合中的键和值都可以使用任意类型。
1 var books = new SortedList<string, string>(); 2 books.Add("C# 2012 wrox box","978-987-9989-7"); 3 books.Add("Professional", "978-987-9989-9"); 4 books["Beginning Visual C# 2008"] = "978-987-9989-8"; 5 books["C# 2008"] = "978-987-9989-5"; 6 7 foreach (KeyValuePair<string,string> book in books) 8 { 9 Console.WriteLine("{0},{1}",book.Key,book.Value); 10 }
输出默认按键的顺序输出。
字典表示一种非常复杂的数据结构,这种数据结构允许按照某个键来访问元素字典也称为映射或散列表。字典的主要特性是能根据键快速查找值 。也可以自由添加和删除元素,但 没有在 内存中移动后续元素的性能开销。
1 Dictionary<int, int> dic = new Dictionary<int, int>(); 2 dic.Add(1, 1); 3 dic[2] = 2; 4 dic[3] = 3; 5 dic.Add(4,4); 6 dic.Remove(2); 7 foreach (var item in dic) 8 { 9 Console.WriteLine("key:{0},Value:{1}",item.Key,item.Value); 10 }
2.7.1 有序字典
SortedDictionary<TKey,TValue>类是一个二叉搜索树,其中的元素根据键来排序。
2.8 集合
包含不重复元素的集合称为"集" 。 .NET4包 含两个集(HashSet<T>(无序)和SortedList<T>(有序))。
1 var set1 = new HashSet<int>() { 1, 2, 3, 4, 5 }; 2 var set2 = new HashSet<int>() { 4, 5, 6, 7, 8 }; 3 set1.ExceptWith(set2); 4 foreach (var item in set1) 5 { 6 Console.WriteLine(item); 7 } 8 9 10 set1.UnionWith(set2); 11 12 foreach (var item in set1) 13 { 14 Console.WriteLine(item); 15 }
2.9可观察的集合
如果需要集合中的元素何时删除或添加的信息,就可以使用ObservableCollection<T>类,这个类是为WPF定义的,这样UI就可以知道集合的变化。这个类需要映入程序集WindowBase,
1 var date =new ObservableCollection<string>(); 2 date.CollectionChanged += Date_CollectionChanged; 3 date.Add("1"); 4 date.Insert(0, "2"); 5 date.Remove("1"); 6 Console.ReadKey(); 7 private static void Date_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 8 { 9 Console.WriteLine("action{0}",e.Action.ToString()); 10 if (e.OldItems != null) 11 { 12 Console.WriteLine("starting index for old item(s):{0}",e.OldStartingIndex); 13 Console.WriteLine("OldItem(s):"); 14 foreach (var item in e.OldItems) 15 { 16 Console.WriteLine(item); 17 } 18 } 19 if (e.NewItems != null) 20 { 21 Console.WriteLine("starting index for new item(s):{0}", e.NewStartingIndex); 22 Console.WriteLine("NewItem(s):"); 23 foreach (var item in e.NewItems) 24 { 25 Console.WriteLine(item); 26 } 27 } 28 Console.WriteLine(); 29 }
为了对集合进行线程安全的访问,定义了IProducerConsumerCollection<T>接口,这个接口重要的方法是TryAdd() (尝试给集合添加一项,如果集合禁止添加,这个操作就可能失败,返回一个Bool值)和TryTake()(工作方式和TryAdd相同,以通知调用者操作是成功还是失败,并在操作成功后返回集合中的项).
1 var sharedCollection = new BlockingCollection<int>(); 2 var events = new ManualResetEventSlim[2]; 3 var waits = new WaitHandle[2]; 4 for (int i = 0; i < 2; i++) 5 { 6 events[i] = new ManualResetEventSlim(false); 7 waits[i] = events[i].WaitHandle; 8 } 9 10 var producer = new Thread(obj=> { var state = (Tuple<BlockingCollection<int>,ManualResetEventSlim>)obj; 11 var coll = state.Item1; 12 var ev = state.Item2; 13 var r = new Random(); 14 for (int i = 0; i < 300; i++) 15 { 16 coll.Add(r.Next(3000)); 17 ev.Set(); 18 } 19 }); 20 21 producer.Start(Tuple.Create<BlockingCollection<int>, ManualResetEventSlim>(sharedCollection, events[0])); 22 23 var consumer = new Thread(obj=> { 24 var state = (Tuple<BlockingCollection<int>, ManualResetEventSlim>)obj; 25 var coll = state.Item1; 26 var ev = state.Item2; 27 28 for (int i = 0; i < 300; i++) 29 { 30 int result = coll.Take(); 31 } 32 ev.Set(); 33 }); 34 35 consumer.Start(Tuple.Create<BlockingCollection<int>,ManualResetEventSlim>(sharedCollection,events[1])); 36 37 if (!WaitHandle.WaitAll(waits)) 38 Console.WriteLine("wait failed"); 39 else 40 Console.WriteLine("reading/writing finished"); 41 42 Console.ReadKey();