zoukankan      html  css  js  c++  java
  • 《C#本质论》读书笔记(16)构建自定义集合

    16.1 更多集合接口

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



    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> 接口。该接口有一个 CompareTo() 方法,返回一个整数,指出传递元素是大于、小于还是等于当前元素,所以,键的数据类型必须实现 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. }    


    16.2 主要集合类

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

    16.2.1 列表集合:List<T>

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

    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>

    和列表集合不同,字典类存储是“名称/值”对。
     插入元素,一个选择是使用 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. }  

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


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

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

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


     键中元素采用的是字幕顺序,而不是数值顺序,这是由于键是字符串,而不是整数。
    在一个已排序的字典集合中插入或删除元素时,由于要保持集合中的元素顺序,所以相对前面的 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)一系列值。
    未完待续。。。









  • 相关阅读:
    How to function call using 'this' inside forEach loop
    jquery.validate.unobtrusive not working with dynamic injected elements
    Difference between jQuery.extend and jQuery.fn.extend?
    Methods, Computed, and Watchers in Vue.js
    Caution using watchers for objects in Vue
    How to Watch Deep Data Structures in Vue (Arrays and Objects)
    Page: DOMContentLoaded, load, beforeunload, unload
    linux bridge
    linux bridge
    EVE-NG网卡桥接
  • 原文地址:https://www.cnblogs.com/tangge/p/6088257.html
Copyright © 2011-2022 走看看