16.1 更多集合接口

集合类(这里指IEnumerable层次结构)实现的接口层次结构




16.1.1 IList<T>与IDictionary<TKey,TValue>

字典类一般只按照键进行索引,而不按位置索引。
列表“键”总是一个整数,“键集”总是从0开始的非负整数的一个连续集合。
解决数据存储或数据获取问题时,考虑 ], list[6]);

  • list.Remove("Grumpy");


  • 16.2.3 搜索List<T>

    要在 List<T> 查找特定的元素,可以使用 Contains() 、 IndexOf() 、 LastIndexOf() 和 BinarySerch() 方法。
       BinarySerch() 采用的是快得多的二分搜索算法,但要求元素已经排序好。一个有用的功能是假如元素没找到,会返回一个负整数。该值的按位取反(~)结果是”大于被查找元素的下一个元素“的索引,如果没有更大的值,则是元素的总数。这样就可以在特定位置方便插入新值。
    1. List<string> list = new List<string>();

    2. int search;

    3. list.Add("public");

    4. list.Add("protected");

    5. list.Add("private");

    6. list.Sort();

    7. search = list.BinarySearch("protected internal");

    8. if (search < 0)

    9. {

    10. list.Insert(~search, "protected internal");

    11. }

    12. foreach (string accessModifier in list)

    13. {

    14. Console.WriteLine(accessModifier);

    15. }


    高级主题:使用 FindAll() 查找多个数据项

       FindAll() 获取 Predicate<T> 类型的一个参数,它是对称为“委托”的一个方法的引用
    1. public static void Main()

    2. {

    3. List<int> list = new List<int>();

    4. list.Add(1);

    5. list.Add(2);

    6. list.Add(3);

    7. list.Add(2);

    8. list.Add(4);

    9. List<int> results = list.FindAll(Even);

    10. foreach (int number in results)

    11. {

    12. Console.WriteLine(number);

    13. }

    14. //2,2,4

    15. Console.Read();

    16. }

    17. public static bool Even(int value)

    18. {

    19. return (value % 2) == 0;

    20. }


    传递一个委托实例 Even() 。若整数实参值是偶数,就返回 true 。

    16.2.4 字典集合:Dictonary<TKey,TValue>

    和列表集合不同,字典类存储是“名称/值”对。
     插入元素,一个选择是使用 Add() 方法。
    1. Dictionary<Guid, string> dictionary =

    2. new Dictionary<Guid, string>();

    3. Guid key = Guid.NewGuid();

    4. dictionary.Add(key, "object");

    还有个选择是索引操作符

    1. Dictionary<Guid, string> dictionary =

    2. new Dictionary<Guid, string>();

    3. Guid key = Guid.NewGuid();

    4. dictionary[key] = "object";

    5. dictionary[key] = "byte";

    由于键和值都要添加到字典中,所以用于枚举字典中的元素的 foreach 循环的循环变量必须是 KeyValuePair<TKey,TValue> 。

    1. Dictionary<string, string> dictionary = new

    2. Dictionary<string, string>();

    3. int index = 0;

    4. dictionary.Add(index++.ToString(), "object");

    5. dictionary.Add(index++.ToString(), "byte");

    6. dictionary.Add(index++.ToString(), "uint");

    7. dictionary.Add(index++.ToString(), "ulong");

    8. dictionary.Add(index++.ToString(), "float");

    9. dictionary.Add(index++.ToString(), "char");

    10. dictionary.Add(index++.ToString(), "bool");

    11. dictionary.Add(index++.ToString(), "ushort");

    12. dictionary.Add(index++.ToString(), "decimal");

    13. dictionary.Add(index++.ToString(), "int");

    14. dictionary.Add(index++.ToString(), "sbyte");

    15. dictionary.Add(index++.ToString(), "short");

    16. dictionary.Add(index++.ToString(), "long");

    17. dictionary.Add(index++.ToString(), "void");

    18. dictionary.Add(index++.ToString(), "double");

    19. dictionary.Add(index++.ToString(), "string");

    20. Console.WriteLine("Key  Value    Hashcode");

    21. Console.WriteLine("---  -------  --------");

    22. foreach (KeyValuePair<string, string> i in dictionary)

    23. {

    24. Console.WriteLine("{0,-5}{1,-9}{2}",

    25. i.Key, i.Value, i.Key.GetHashCode());

    26. }

     如果只处理字典中的键或值,那么可以用 Keys 和 Values 属性。这些属性返回的数据类型是 ICollection<T> 。他们返回的是对原始字典集合中的数据的引用,而不是返回的副本。


    16.2.5 已排序集合:SortedDictionary<TKey,TValue>和SortedList<T>

    已排序集合类的元素是已经排好序的。具体说对于 SortedDictionary<TKey,TValye> 元素是按照键排序的;对于 SortedList<T> ,元素是按照值排序的(还有一个非泛型的  SortedList 实现)。

    1. SortedDictionary<string, string> sortedDictionary =

    2. new SortedDictionary<string, string>();

    3. int index = 0;

    4. sortedDictionary.Add(index++.ToString(), "object");

    5. sortedDictionary.Add(index++.ToString(), "byte");

    6. sortedDictionary.Add(index++.ToString(), "uint");

    7. sortedDictionary.Add(index++.ToString(), "ulong");

    8. sortedDictionary.Add(index++.ToString(), "float");

    9. sortedDictionary.Add(index++.ToString(), "char");

    10. sortedDictionary.Add(index++.ToString(), "bool");

    11. sortedDictionary.Add(index++.ToString(), "ushort");

    12. sortedDictionary.Add(index++.ToString(), "decimal");

    13. sortedDictionary.Add(index++.ToString(), "int");

    14. sortedDictionary.Add(index++.ToString(), "sbyte");

    15. sortedDictionary.Add(index++.ToString(), "short");

    16. sortedDictionary.Add(index++.ToString(), "long");

    17. sortedDictionary.Add(index++.ToString(), "void");

    18. sortedDictionary.Add(index++.ToString(), "double");

    19. sortedDictionary.Add(index++.ToString(), "string");

    20. Console.WriteLine("Key  Value    Hashcode");

    21. Console.WriteLine("---  -------  ----------");

    22. foreach (

    23. KeyValuePair<string, string> i in sortedDictionary)

    24. {

    25. Console.WriteLine("{0,-5}{1,-9}{2}",

    26. i.Key, i.Value, i.Key.GetHashCode());

    27. }


     键中元素采用的是字幕顺序,而不是数值顺序,这是由于键是字符串,而不是整数。
    在一个已排序的字典集合中插入或删除元素时,由于要保持集合中的元素顺序,所以相对前面的 Dictionary<TKey,TValue> 执行事件要稍微长一些。它内部使用两个数组,一个用于键的检索,一个勇于索引的检索。
    对于 System.Collections.Sorted 排序列表,索引操作是通过 GetByIndex() 和 SetByIndex() 方法来支持的。
    对于 System.Collections.Generic.SortedList<TKey,TValue> ,Keys 和 Values 属性分别返回 IList<TKey> 和 IList<TValue> 实例。这些方法使得已排序列表具有字典行为,也有列表类型的集合的行为。

    16.2.6 栈集合:Stack<T>

    栈集合被设计为:后进先出
    两个方法:
    Push():插入元素。
    Pop():按照与添加时相反的顺序获取并删除元素。
     为了不修改栈的前提下访问栈中的元素,使用 Peek() 和 Contains() 方法。
     Peek() :返回 Pop() 将获取的下一个元素。
     Contains() :勇于判断一个元素是否存在于栈的某个地方。

    16.2.7队列集合:Queue<T>

    队列集合类和栈集合类基本相同,遵循先入先出模式
     Enqueue() :入队
     Dequeue() :出队。
    队列集合根据需要自动增大。但缩小时不一定回收之前使用的存储空间,因为这会使插入新元素的动作变得很昂贵。如果确定队列长时间大小不变,可以使用 TrimToSize() 方法提醒队列集合你希望回收存储空间。

    16.2.8 链表:LinkedList<T>

     链表允许正向和反向遍历。(没有对应的非泛型类型)

    16.4 返回null或者空集合

    返回数组或集合时,必须允许返回 null ,或者返回不包含任何数据的集合实例。
    通常,返回没有数据的集合实例是更好的选择,可避免遍历集合数据前检查 null 值。
    但是这个准则也有例外,比如 null 被有意的用来表示有别于“零个项目”的情况。
    例如,网站用户名集合可能会是 null ,以此来表示出于某种原因未获得最新集合。

    16.5 迭代器

    本节讨论利用迭代器为自定义集合实现自己的 IEnumerator<T> 、 IEnumerable<T> 和对应的非泛型接口。
       加入某个类希望支持 foreach 进行迭代,就必须实现枚举器( enumerator )模式。

    16.5.1 迭代器定义

    迭代器是实现类的方法的一个途径,是更加复杂的枚举数模式的语法简化形式。由于在生成的CIL代码中仍然采用枚举数模式,所以并不会带来真正的运行时性能优势。不过,使用迭代器而不是手动实现枚举数模式,能显著提高程序员的编程效率。

    16.5.2 迭代器语法

    迭代器提供了迭代器接口(也就是 IEnumerator<T> 和 IEnumerable<T> 的组合)的一个快捷实现。
    创建一个 GetEnumerator() 方法,表示声明了一个迭代器。接着要添加对迭代器接口的支持
    1. public IEnumerator<T> GetEnumerator()

    2. {

    3. //...

    4. return new List<T>.Enumerator();//This will be implimented in 16.16

    5. }


    16.1.3 从迭代器生成值

    迭代器类似于函数,但它不返(renturn)值,而是生成(yield)一系列值。
    未完待续。。。





    《C#本质论》读书笔记(16)构建自定义集合的更多相关文章

    1. 十六、C# 常用集合类及构建自定义集合(使用迭代器)

      常用集合类及构建自定义集合 1.更多集合接口:IList<T>.IDictionary<TKey,TValue>.IComparable<T>.ICollectio ...

    2. 16位模式/32位模式下PUSH指令探究——《x86汇编语言:从实模式到保护模式》读书笔记16

      一.Intel 32 位处理器的工作模式 如上图所示,Intel 32 位处理器有3种工作模式. (1)实模式:工作方式相当于一个8086 (2)保护模式:提供支持多任务环境的工作方式,建立保护机制 ...

    3. Node.js高级编程读书笔记 - 4 构建Web应用程序

      Outline 5 构建Web应用程序 5.1 构建和使用HTTP中间件 5.2 用Express.js创建Web应用程序 5.3 使用Socket.IO创建通用的实时Web应用程序 5 构建Web应 ...

    4. 《java并发编程实战》读书笔记11--构建自定义的同步工具,条件队列,Condition,AQS

      第14章 构建自定义的同步工具 本章将介绍实现状态依赖性的各种选择,以及在使用平台提供的状态依赖机制时需要遵守的各项规则. 14.1 状态依赖性的管理 对于并发对象上依赖状态的方法,虽然有时候在前提条 ...

    5. ArcGIS API for JavaScript 4.2学习笔记[16] 弹窗自定义功能按钮及为要素自定义按钮(第五章完结)

      这节对Popups这一章的最后两个例子进行介绍和解析. 第一个[Popup Actions]介绍了弹窗中如何自定义工具按钮(名为actions),以PopupTemplate+FeatureLayer ...

    6. OCA读书笔记(16) - 执行数据库恢复

      16. Performing Database Recovery 确定执行恢复的必要性访问不同接口(EM以及命令行)描述和使用可用选项,如RMAN和Data Recovery Advisor执行恢复- ...

    7. 流处理与消息队列------《Designing Data-Intensive Applications》读书笔记16

      上一篇聊了聊批处理的缺点,对于无界数据来说,流处理会是更好的选择,"流"指的是随着时间的推移逐步增加的数据.消息队列可以将这些流组织起来,快速的在应用程序中给予反馈.但是消息队列与 ...

    8. 《Java Concurrency》读书笔记,构建线程安全应用程序

      1. 什么是线程安全性 调用一个函数(假设该函数是正确的)操作某对象常常会使该对象暂时陷入不可用的状态(通常称为不稳定状态),等到操作完全结束,该对象才会重新回到完全可用的状态.如果其他线程企图访问一 ...

    9. 【读书笔记】构建之法(CH4~CH6)

      从chapter4至chapter6,围绕着构建过程的合作讨论构建之法,而合作与个人工作的区别却以一个微妙的问题为开端:阅读别人的代码有多难? 两人合作:(驾驶员与领航员) 合作要注意代码风格规范与设 ...

    随机推荐

    1. Function构造函数

      使用Function构造函数, 也能够创建函数, 和使用关键字function定义函数有几点区别: 使用function关键字这样定义函数: var f = function(x,y) {return ...

    2. Vue.js之v-for

      v-for标签可以用来遍历数组,将数组的每一个值绑定到相应的视图元素中去,此外,v-for还可以遍历对象的属性,并且可以和template模板元素一起使用. 一.迭代数组 html: <ul&g ...

    3. BZOJ 1968: [Ahoi2005]COMMON 约数研究

      1968: [Ahoi2005]COMMON 约数研究 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 2032  Solved: 1537[Submit] ...

    4. opencv 比较直方图方式 进行人脸检测对比

      完整opencv(emgucv)人脸.检测.采集.识别.匹配.对比 //成对几何直方图匹配               public static string MatchHist()         ...

    5. python面向对象进阶(八)

      上一篇<Python 面向对象初级(七)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...

    6. 写个c++小例子

      class Rational{ public: const Rational operator*( const Rational& rhs); Rational(int num); priva ...

    7. hibernate UUID问题

      前言:hibernate对于字符串类型主键支持UUID主键生成策略,(号称是世界上唯一的字符串) 运行环境:运行环境:hibernate5.2,mysql5.6 一,使用hibernate给Strin ...

    8. Emgu.CV/opencv 绘图 线面文字包括中文

      绘图很简单 Emgu.CV.Image<Bgr, Byte> image;   使用image.Draw可以画各种图形和文字包括英文及数字,不支持中文   CircleF circle = ...

    9. 作为一名前端er,从武汉来到深圳三个月有感

      来到深圳已经三个月了,从最开始的担心自己的能力不够怕不能够在深圳这个互联网产品及其发达的城市立足下来,到现在已经慢慢地拾起了一丁点的信心了 (虽然还有很多知识是不够的.但是相当于之前我的,我是觉得我已 ...

    10. 什么叫session和cookie-及其设置

      http的无状态? 保持状态, 是指当程序关闭后重启, 上一次操作的历史还能继续, 保持的. 如word中的 "选项"设置. 如windows系统的设置等等. http的设计目的, ...