当前位置: 首页 > news >正文

《C#本质论》读书笔记(16)构建自定义集合

16.1 更多集合接口

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

196558-20161201123039943-428962761.png


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

字典类一般只按照键进行索引,而不按位置索引。
列表“键”总是一个整数,“键集”总是从0开始的非负整数的一个连续集合。
解决数据存储或数据获取问题时,考虑     IList<T> (侧重位置索引获取值)与   IDictionary<TKey,TValue> (侧重通过键来获取值)。

16.1.2 ICompatable<T>

ICompatable<T>是实现排序的关键。
例如,  List<T>.Sort() ,你需要采取某种方式比较对象,一个办法就是使用  ICompatable<T> 接口。该接口有一个  Co mpareTo() 方法,返回一个 整数,指出传递元素是大于、小于还是等于当前元素,所以,键的数据类型必须实现  ICompatable<T> 


高级主题:用IComparer<T>排序

        为了实现自定义排序,另一个方法是向排序方法传递实现了  IComparer<T>  的元素。集合中的元素通常不支持这个接口。
     IComparable<T>  IComparer<T> 的区别很细微,但重要。
IComparable<T>  说:“我知道如何将自己和我的类型的另一个实例进行比较
IComparer<T> 说:“我知道如何比较给定类型的两个实例

  1. public static void Main()    

  2. {    

  3.     Contact aaa = new Contact() { LastName = "bbb", FirstName = "ddd" };    

  4.     Contact bbb = new Contact() { LastName = "aaa", FirstName = "ccc" };    

  5.     

  6.     //Console.WriteLine(new NameComparison().Compare(aaa, bbb));    

  7.     

  8.     List<Contact> contactlist = new List<Contact>();    

  9.     contactlist.Add(aaa);    

  10.     contactlist.Add(bbb);    

  11.     

  12.     foreach (var contact in contactlist)    

  13.     {    

  14.         Console.WriteLine(contact.LastName + " ");    

  15.     }    

  16.     //排序    

  17.     contactlist.Sort(new NameComparison());    

  18.     

  19.     foreach (var contact in contactlist)    

  20.     {    

  21.         Console.WriteLine(contact.LastName + " ");    

  22.     }    

  23.     

  24.     Console.Read();    

  25.     

  26. }    

  27.     

  28. class Contact    

  29. {    

  30.     public string FirstName { getset; }    

  31.     public string LastName { getset; }    

  32. }    

  33.     

  34.     

  35. class NameComparison : IComparer<Contact>    

  36. {    

  37.     public int Compare(Contact x, Contact y)    

  38.     {    

  39.         int result;    

  40.     

  41.         if (Contact.ReferenceEquals(x, y))    

  42.         {    

  43.             result = 0;    

  44.         }    

  45.         else    

  46.         {    

  47.             if (x == null)    

  48.             {    

  49.                 result = 1;    

  50.             }    

  51.             else if (y == null)    

  52.             {    

  53.                 result = -1;    

  54.             }    

  55.             else    

  56.             {    

  57.                 result = StringCompare(x.LastName, y.LastName);    

  58.                 if (result == 0)    

  59.                 {    

  60.                     result =    

  61.                         StringCompare(x.FirstName, y.FirstName);    

  62.                 }    

  63.             }    

  64.         }    

  65.         return result;    

  66.     }    

  67.     

  68.     private static int StringCompare(string x, string y)    

  69.     {    

  70.         int result;    

  71.         if (x == null)    

  72.         {    

  73.             if (y == null)    

  74.             {    

  75.                 result = 0;    

  76.             }    

  77.             else    

  78.             {    

  79.                 result = 1;    

  80.             }    

  81.         }    

  82.         else    

  83.         {    

  84.             result = x.CompareTo(y);    

  85.         }    

  86.         return result;    

  87.     }    

  88. }    

196558-20161201123040412-1756400846.png

16.2 主要集合类

共有5类关键的集合类,所有泛型类都位于  System.Collections.Generic命名空间。

16.2.1 列表集合:List<T>

List<T>具有与数组相似的属性。关键在于会自动的扩展,也可以显示调用  TrimToSize()  或  Capacity  来缩小。
196558-20161201123040912-84358752.png

  1. List<string> list = new List<string>();  

  2.      

  3. // Lists automatically expand as elements  

  4. // are added.  

  5. list.Add("Sneezy");  

  6. list.Add("Happy");  

  7. list.Add("Dopey");  

  8. list.Add("Doc");  

  9. list.Add("Sleepy");  

  10. list.Add("Bashful");  

  11. list.Add("Grumpy");  

  12.      

  13. list.Sort();  

  14.      

  15. Console.WriteLine(  

  16.     "In alphabetical order {0} is the "  

  17.     + "first dwarf while {1} is the last.",  

  18.     list[0], list[6]);  

  19.      

  20. 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.   

  4. list.Add("public");  

  5. list.Add("protected");           

  6. list.Add("private");  

  7.   

  8.   

  9. list.Sort();  

  10.   

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

  12. if (search < 0)  

  13. {  

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

  15. }  

  16.   

  17. foreach (string accessModifier in list)  

  18. {  

  19.     Console.WriteLine(accessModifier);  

  20. }  


高级主题:使用 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.   

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

  11.   

  12.     foreach (int number in results)  

  13.     {  

  14.         Console.WriteLine(number);  

  15.     }  

  16.     //2,2,4  

  17.     Console.Read();  

  18.   

  19. }  

  20.   

  21. public static bool Even(int value)  

  22. {  

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

  24. }  


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

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

和列表集合不同,字典类存储是“名称/值”对。
196558-20161201123041709-667363482.png
 插入元素,一个选择是使用  Add() 方法。


  1. Dictionary<Guid, string> dictionary =  

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

  3. Guid key = Guid.NewGuid();  

  4.   

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


还有个选择是索引操作符

  1. Dictionary<Guid, string> dictionary =  

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

  3. Guid key = Guid.NewGuid();  

  4.   

  5. dictionary[key] = "object";  

  6. dictionary[key] = "byte";  


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

  1. Dictionary<stringstring> dictionary = new  

  2.    Dictionary<stringstring>();  

  3.   

  4. int index = 0;  

  5.   

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  22.   

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

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

  25. foreach (KeyValuePair<stringstring> i in dictionary)  

  26. {  

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

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

  29. }  

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


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

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

  1. SortedDictionary<stringstring> sortedDictionary =  

  2.    new SortedDictionary<stringstring>();  

  3.   

  4. int index = 0;  

  5.   

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  22.   

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

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

  25. foreach (  

  26.     KeyValuePair<stringstring> i in sortedDictionary)  

  27. {  

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

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

  30. }  

196558-20161201123042787-1002940235.png

 键中元素采用的是字幕顺序,而不是数值顺序,这是由于键是字符串,而不是整数。
196558-20161201123043162-1980814993.png
在一个已排序的字典集合中插入或删除元素时,由于要保持集合中的元素顺序,所以相对前面的  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():按照与添加时相反的顺序获取并删除元素。
196558-20161201123043724-2098536514.png
 为了不修改栈的前提下访问栈中的元素,使用  Peek()  Contains() 方法。
 Peek() :返回  Pop() 将获取的下一个元素。
 Contains() :勇于判断一个元素是否存在于栈的某个地方。

16.2.7队列集合:Queue<T>

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

16.2.8 链表:LinkedList<T>

 链表允许正向和反向遍历。(没有对应的非泛型类型)
196558-20161201123044568-1085934449.png

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)一系列值。
未完待续。。。







来自为知笔记(Wiz)


相关文章:

  • Android真机抓屏- Android Screen Monitor
  • 20161122
  • 稳定,实际是暴风雨来临前的死寂
  • 单词接龙
  • Debug看方法的调用流程
  • WFS-GetFeature的请求方式和ajax提交方法
  • 杂七杂八(1)——如何查看本机的.NET Framework版本
  • 根据当月数据库自动生成下个月数据库--3
  • Bootstrap3 排版-对齐
  • 用python操作mysql数据库(之简单“插入数据”操作)
  • 数学之高幂次取模
  • iOS 地图缩放级别问题
  • docker学习实践之路[第四站]利用pm2镜像部署node应用
  • 每天一个linux命令(10):cat 命令
  • [树莓派(raspberry pi)] 01、在linux环境下给树莓派安装系统及入门各种资料
  • .pyc 想到的一些问题
  • 「面试题」如何实现一个圣杯布局?
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • 【干货分享】SpringCloud微服务架构分布式组件如何共享session对象
  • android百种动画侧滑库、步骤视图、TextView效果、社交、搜房、K线图等源码
  • angular学习第一篇-----环境搭建
  • Druid 在有赞的实践
  • HTML-表单
  • JavaScript-Array类型
  • JS实现简单的MVC模式开发小游戏
  • magento 货币换算
  • Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel
  • springboot_database项目介绍
  • webpack4 一点通
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 纯 javascript 半自动式下滑一定高度,导航栏固定
  • 判断客户端类型,Android,iOS,PC
  • 使用 5W1H 写出高可读的 Git Commit Message
  • 微信小程序上拉加载:onReachBottom详解+设置触发距离
  • 我与Jetbrains的这些年
  • 新版博客前端前瞻
  • 主流的CSS水平和垂直居中技术大全
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • $(document).ready(function(){}), $().ready(function(){})和$(function(){})三者区别
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (JSP)EL——优化登录界面,获取对象,获取数据
  • (windows2012共享文件夹和防火墙设置
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (十七)devops持续集成开发——使用jenkins流水线pipeline方式发布一个微服务项目
  • (原創) 未来三学期想要修的课 (日記)
  • (转载)Linux 多线程条件变量同步
  • .babyk勒索病毒解析:恶意更新如何威胁您的数据安全
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .Net中ListT 泛型转成DataTable、DataSet
  • .pings勒索病毒的威胁:如何应对.pings勒索病毒的突袭?
  • ??myeclipse+tomcat
  • @RunWith注解作用
  • @SuppressLint(NewApi)和@TargetApi()的区别
  • @在php中起什么作用?