VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > C#编程 >
  • C#教程之C# 基础知识系列- 3 集合数组(2)

本站最新发布   C#从入门到精通
试听地址  
https://www.xin3721.com/eschool/CSharpxin3721/

的使用方式也跟字典一样,通过索引访问和操作数据。

1.4.1 初始化

Dictionary的初始化有如下几个方法:

Dictionary<string, int> dict = new Dictionary<string, int>();// 键是字符串,值是int类型
Dictionary<string,int> dict1 = new Dictionary<string, int>(10);// 指定初始容量是10
Dictionary<string,int> dict2 = new Dictionary<string, int>()
{
	{"1",1},
	{"2",2}
};// 在大括号标记中 通过 {key,value}的写法创建一个 字典对象,并包含这些键值对

// 传入一个字典对象,以传入的对象为基础创建一个字典
Dictionary<string,int> dict3 = new Dictionary<string, int>(dict2);

1.4.2 常用方法

  1. 添加元素

    Dictionary<string, int> dict = new Dictionary<string, int>();
    // 方法一
    dict.Add("1",2);//添加一个 键为“1”,值为2的键值对。
    //方法二
    //字典可以类似列表的形式通过下标添加或更新键对应的值,
    //不过与列表不同的是,字典的下标是字符串
    dict["2"] = 4;// 如果 dict中2有值,则更新为4,如果没有,则设置2对应的值为4
    
  2. 获取元素

    Dictionary<string, int> dict = new Dictionary<string, int>();
    /*
    省略数据填充阶段
    */
    int value = dict["2"]; // value = 4
    // 如果Dictionary中不存在索引为“2”的数据
    // 将会抛出 System.Collections.Generic.KeyNotFoundException 异常
    

    C# 的Dictionary还有一个TryGetValue方法可以用来尝试获取,他的使用方法是这样的:

    int obj = 0;
    boolean isContains = dict.TryGetValue("3", out obj);
    // 方法会返回 dict是否包含键“3”的结果,如果有 obj 则存放了dict中对应的值,如果没有,则返回false且不改变 obj 的值
    
  3. Count

    获取Dictionary里键值对的数量。

    int count = dict.Count;
    

    Dictionary没有LongCount属性,因为对于Dictionary存放数据需要比对Key的相等性,如果存放巨量数据将会对数据的访问和操作效率有影响。

  4. Keys

    获取Dictionary里所有的键,返回一个KeyCollection对象,不需要关心这是一个什么类型,可以简单的把它当做一个存放了键的HashSet

  5. ContainsKey()

    是否包含键:通常与获取元素一起使用,可以先判断Dictionary里是否有这个键,然后再进行后续操作。

  6. Remove()

    删除Dictionary中键对应的元素,删除后再次访问会报错。如果删除一个不存在的元素将返回flase。
    操作示例:

    Dictionary<string,int> dict = new Dictionary<string, int>();
    //省略赋值操作
    bool result = dict.Remove("2");// 如果dict里包含键为“2”的元素,则result为true,否则为false
    

    另一种方法:

    int value = 0;
    bool result = dict.Remove("2", out value);
    // 如果dict 里包含键为“2”的元素,则result 为 false且value为对应的值
    

1.4.3 不常用但有用的方法

  1. ContainsValue()

    是否包含值,与ContainsKey的用法一样,只不过遍历的是值;用处不大。

  2. Values

    获取值的集合类似与KeyValues

2. 传统集合(非泛型)

C#的传统集合基本都存放在System.Collections命名空间里,详细的可以查看微软官方文档。这个命名空间里的集合类使用都不多,不过C#的集合体系的接口规范都是在这个里面定义的。

2.1 常见类介绍

  1. ArrayList List的非泛型版,与List操作方法一致,不过返回值是Object类型

  2. SortedList 一个排序的键值对集合,我没用过,不过官方给了如下示例:

    using System;
    using System.Collections;
    public class SamplesSortedList  {
    
    	 public static void Main()  {
    
    			// Creates and initializes a new SortedList.
    			SortedList mySL = new SortedList();
    			 mySL.Add("Third", "!");
    			 mySL.Add("Second", "World");
    			 mySL.Add("First", "Hello");
    
    			// Displays the properties and values of the SortedList.
    			Console.WriteLine( "mySL" );
    			Console.WriteLine( "  Count:    {0}", mySL.Count );
    			Console.WriteLine( "  Capacity: {0}", mySL.Capacity );
    			Console.WriteLine( "  Keys and Values:" );
    			PrintKeysAndValues( mySL );
    	 }
    
    	 public static void PrintKeysAndValues( SortedList myList )  {
    			Console.WriteLine( "\t-KEY-\t-VALUE-" );
    			for ( int i = 0; i < myList.Count; i++ )  {
    				 Console.WriteLine( "\t{0}:\t{1}", myList.GetKey(i), myList.GetByIndex(i) );
    			}
    			Console.WriteLine();
    	 }
    }
    
  3. HashTable表示根据键的哈希代码进行组织的键/值对的集合。HashTable的结构类似于Dictionary但又与其不同,它的键值存储用的是Hash值。以下是官方给出的示例代码:

    using System;
    using System.Collections;
    
    class Example
    {
    		public static void Main()
    		{
    				// Create a new hash table.
    				//
    				Hashtable openWith = new Hashtable();
    
    				// Add some elements to the hash table. There are no 
    				// duplicate keys, but some of the values are duplicates.
    				openWith.Add("txt", "notepad.exe");
    				openWith.Add("bmp", "paint.exe");
    				openWith.Add("dib", "paint.exe");
    				openWith.Add("rtf", "wordpad.exe");
    
    				// The Add method throws an exception if the new key is 
    				// already in the hash table.
    				try
    				{
    						openWith.Add("txt", "winword.exe");
    				}
    				catch
    				{
    						Console.WriteLine("An element with Key = \"txt\" already exists.");
    				}
    
    				// The Item property is the default property, so you 
    				// can omit its name when accessing elements. 
    				Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);
    
    				// The default Item property can be used to change the value
    				// associated with a key.
    				openWith["rtf"] = "winword.exe";
    				Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);
    
    				// If a key does not exist, setting the default Item property
    				// for that key adds a new key/value pair.
    				openWith["doc"] = "winword.exe";
    
    				// ContainsKey can be used to test keys before inserting 
    				// them.
    				if (!openWith.ContainsKey("ht"))
    				{
    						openWith.Add("ht", "hypertrm.exe");
    						Console.WriteLine("Value added for key = \"ht\": {0}", openWith["ht"]);
    				}
    
    				// When you use foreach to enumerate hash table elements,
    				// the elements are retrieved as KeyValuePair objects.
    				Console.WriteLine();
    				foreach( DictionaryEntry de in openWith )
    				{
    						Console.WriteLine("Key = {0}, Value = {1}", de.Key, de.Value);
    				}
    
    				// To get the values alone, use the Values property.
    				ICollection valueColl = openWith.Values;
    
    				// The elements of the ValueCollection are strongly typed
    				// with the type that was specified for hash table values.
    				Console.WriteLine();
    				foreach( string s in valueColl )
    				{
    						Console.WriteLine("Value = {0}", s);
    				}
    
    				// To get the keys alone, use the Keys property.
    				ICollection keyColl = openWith.Keys;
    
    				// The elements of the KeyCollection are strongly typed
    				// with the type that was specified for hash table keys.
    				Console.WriteLine();
    				foreach( string s in keyColl )
    				{
    						Console.WriteLine("Key = {0}", s);
    				}
    
    				// Use the Remove method to remove a key/value pair.
    				Console.WriteLine("\nRemove(\"doc\")");
    				openWith.Remove("doc");
    
    				if (!openWith.ContainsKey("doc"))
    				{
    						Console.WriteLine("Key \"doc\" is not found.");
    				}
    		}
    }
    
    /* This code example produces the following output:
    
    An element with Key = "txt" already exists.
    For key = "rtf", value = wordpad.exe.
    For key = "rtf", value = winword.exe.
    Value added for key = "ht": hypertrm.exe
    
    Key = dib, Value = paint.exe
    Key = txt, Value = notepad.exe
    Key = ht, Value = hypertrm.exe
    Key = bmp, Value = paint.exe
    Key = rtf, Value = winword.exe
    Key = doc, Value = winword.exe
    
    Value = paint.exe
    Value = notepad.exe
    Value = hypertrm.exe
    Value = paint.exe
    Value = winword.exe
    Value = winword.exe
    
    Key = dib
    Key = txt
    Key = ht
    Key = bmp
    Key = rtf
    Key = doc
    
    Remove("doc")
    Key "doc" is not found.
     */
    

    虽然C#框架保留了非泛型集合元素,但不建议使用非泛型集合进行开发。

3 一些不常用的集合类

除了之前所说的几个集合类,C#还设置了一些在开发中不常用但在特定场合很有用的集合类。

3.1 Queue<T> 和 Queue

这两个类是一对的,一个是泛型类,一个是非泛型类。该类中文名称是队列,如其名,队列讲究一个先进先出,所以队列每次取元素都是从头取,存放是放到队列尾。
操作代码如下:

  1. 加入队列

    Queue queue = new Queue();
    queue.Enqueue(1);
    queue.Enqueue("2");
    
    Queue<string> queue1 = new Queue<string>();
    queue1.Enqueue("stri");//
    
  2. 读取队首的元素
    读取有两种:

    • 读取但不移除元素:

      object obj= queue.Peek();
      string str = queue.Peek();
      
    • 读取并移除元素:

      object obj = queue.Dequeue();
      string str = queue.Dequeue();
      
    1. Count 获取元素数量

3.2 LinkedList<T>

LinkedList,链表。与List不同的地方是,LinkedList的元素是LinkedListNode对象,该对象有四个属性,分别是List
-指向列表对象,Previous指向前一个对象如果有的话,Next指向后一个对象如果有的话。所以根据元素的属性可以发现链表的工作方式,链表就像一条锁链一样,一个元素分三块,一个指向前一个元素,一个用来存放值,一个指向下一个元素,简单如下图所示:
file
所以可以明显的发现LinkedList在随机插取上比一般的要快,因为它不用维护一个数组,但是在查找和坐标操作上明显要慢很多。
LinkedList简单介绍这么多,可以看看它的一些常见操作:

  1. First 第一个元素

    获取第一个元素

  2. Last 最后一个元素

    获取最后一个元素

  3. AddAfter/AddBefore
    在某个节点后/在某个节点前插入数据
    支持以下参数列表:

    • (LinkedListNode node, T value)
    • (LinkedListNode node, LinkedListNode newNode)

    第一个参数表示要插入的节点位置,第二个表示要插入的节点/元素。第一个参数会校验是否属于该链表,如果不属于则会抛出一个异常。第二个可以是值,也可以是初始化好的节点对象。如果是节点对象,则判断是否归属其他链表,如果是其他链表抛出异常。

  4. AddFirst/AddLast

    添加元素到头或者尾,可以使用LinkedListNode或者添加值。

  5. Remove

    删除,可以传递某个节点,或者要删除的节点里存放的值。

  6. RemoveFirst/RemoveLast
    删除第一个节点,删除最后一个节点,不含参数

下面是微软官方的一些示例

using System;
using System.Text;
using System.Collections.Generic;

public class Example
{
    public static void Main()
    {
        // Create the link list.
        string[] words =
            { "the", "fox", "jumps", "over", "the", "dog" };
        LinkedList<string> sentence = new LinkedList<string>(words);
        Display(sentence, "The linked list values:");
        Console.WriteLine("sentence.Contains(\"jumps\") = {0}",
            sentence.Contains("jumps"));

        // Add the word 'today' to the beginning of the linked list.
        sentence.AddFirst("today");
        Display(sentence, "Test 1: Add 'today' to beginning of the list:");

        // Move the first node to be the last node.
        LinkedListNode<string> mark1 = sentence.First;
        sentence.RemoveFirst();
        sentence.AddLast(mark1);
        Display(sentence, "Test 2: Move first node to be last node:");

        // Change the last node to 'yesterday'.
        sentence.RemoveLast();
        sentence.AddLast("yesterday");
        Display(sentence, "Test 3: Change the last node to 'yesterday':");

        // Move the last node to be the first node.
        mark1 = sentence.Last;
        sentence.RemoveLast();
        sentence.AddFirst(mark1);
        Display(sentence, "Test 4: Move last node to be first node:");

        // Indicate the last occurence of 'the'.
        sentence.RemoveFirst();
        LinkedListNode<string> current = sentence.FindLast("the");
        IndicateNode(current, "Test 5: Indicate last occurence of 'the':");

        // Add 'lazy' and 'old' after 'the' (the LinkedListNode named current).
        sentence.AddAfter(current, "old");
        sentence.AddAfter(current, "lazy");
        IndicateNode(current, "Test 6: Add 'lazy' and 'old' after 'the':");

        // Indicate 'fox' node.
        current = sentence.Find("fox");
        IndicateNode(current, "Test 7: Indicate the 'fox' node:");

        // Add 'quick' and 'brown' before 'fox':
        sentence.AddBefore(current, "quick");
        sentence.AddBefore(current, "brown");
        IndicateNode(current, "Test 8: Add 'quick' and 'brown' before 'fox':");

        // Keep a reference to the current node, 'fox',
        // and to the previous node in the list. Indicate the 'dog' node.
        mark1 = current;
        LinkedListNode<string> mark2 = current.Previous;
        current = sentence.Find("dog");
        IndicateNode(current, "Test 9: Indicate the 'dog' node:");

        // The AddBefore method throws an InvalidOperationException
        // if you try to add a node that already belongs to a list.
        Console.WriteLine("Test 10: Throw exception by adding node (fox) already in the list:");
        try
        {
            sentence.AddBefore(current, mark1);
        }
        catch (InvalidOperationException ex)
        {
            Console.WriteLine("Exception message: {0}", ex.Message);
        }
        Console.WriteLine();

        // Remove the node referred to by mark1, and then add it
        // before the node referred to by current.
        // Indicate the node referred to by current.
        sentence.Remove(mark1);
        sentence.AddBefore(current, mark1);
        IndicateNode(current, "Test 11: Move a referenced node (fox) before the current node (dog):");

        // Remove the node referred to by current.
        sentence.Remove(current);
        IndicateNode(current, "Test 12: Remove current node (dog) and attempt to indicate it:");

        // Add the node after the node referred to by mark2.
        sentence.AddAfter(mark2, current);
        IndicateNode(current, "Test 13: Add node removed in test 11 after a referenced node (brown):");

        // The Remove method finds and removes the
        // first node that that has the specified value.
        sentence.Remove("old");
        Display(sentence, "Test 14: Remove node that has the value 'old':");

        // When the linked list is cast to ICollection(Of String),
        // the Add method adds a node to the end of the list.
        sentence.RemoveLast();
        ICollection<string> icoll = sentence;
        icoll.Add("rhinoceros");
        Display(sentence, "Test 15: Remove last node, cast to ICollection, and add 'rhinoceros':");

        Console.WriteLine("Test 16: Copy the list to an array:");
        // Create an array with the same number of
        // elements as the inked list.
        string[] sArray = new string[sentence.Count];
        sentence.CopyTo(sArray, 0);

        foreach (string s in sArray)
        {
            Console.WriteLine(s);
        }

        // Release all the nodes.
        sentence.Clear();

        Console.WriteLine();
        Console.WriteLine("Test 17: Clear linked list. Contains 'jumps' = {0}",
            sentence.Contains("jumps"));

        Console.ReadLine();
    }

    private static void Display(LinkedList<string> words, string test)
    {
        Console.WriteLine(test);
        foreach (string word in words)
        {
            Console.Write(word + " ");
        }
        Console.WriteLine();
        Console.WriteLine();
    }

    private static void IndicateNode(LinkedListNode<string> node, string test)
    {
        Console.WriteLine(test);
        if (node.List == null)
        {
            Console.WriteLine("Node '{0}' is not in the list.\n",
                node.Value);
            return;
        }

        StringBuilder result = new StringBuilder("(" + node.Value + ")");
        LinkedListNode<string> nodeP = node.Previous;

        while (nodeP != null)
        {
            result.Insert(0, nodeP.Value + " ");
            nodeP = nodeP.Previous;
        }

        node = node.Next;
        while (node != null)
        {
            result.Append(" " + node.Value);
            node = node.Next;
        }

        Console.WriteLine(result);
        Console.WriteLine();
    }
}

//This code example produces the following output:
//
//The linked list values:
//the fox jumps over the dog

//Test 1: Add 'today' to beginning of the list:
//today the fox jumps over the dog

//Test 2: Move first node to be last node:
//the fox jumps over the dog today

//Test 3: Change the last node to 'yesterday':
//the fox jumps over the dog yesterday

//Test 4: Move last node to be first node:
//yesterday the fox jumps over the dog

//Test 5: Indicate last occurence of 'the':
//the fox jumps over (the) dog

//Test 6: Add 'lazy' and 'old' after 'the':
//the fox jumps over (the) lazy old dog

//Test 7: Indicate the 'fox' node:
//the (fox) jumps over the lazy old dog

//Test 8: Add 'quick' and 'brown' before 'fox':
//the quick brown (fox) jumps over the lazy old dog

//Test 9: Indicate the 'dog' node:
//the quick brown fox jumps over the lazy old (dog)

//Test 10: Throw exception by adding node (fox) already in the list:
//Exception message: The LinkedList node belongs a LinkedList.

//Test 11: Move a referenced node (fox) before the current node (dog):
//the quick brown jumps over the lazy old fox (dog)

//Test 12: Remove current node (dog) and attempt to indicate it:
//Node 'dog' is not in the list.

//Test 13: Add node removed in test 11 after a referenced node (brown):
//the quick brown (dog) jumps over the lazy old fox

//Test 14: Remove node that has the value 'old':
//the quick brown dog jumps over the lazy fox

//Test 15: Remove last node, cast to ICollection, and add 'rhinoceros':
//the quick brown dog jumps over the lazy rhinoceros

//Test 16: Copy the list to an array:
//the
//quick
//brown
//dog
//jumps
//over
//the
//lazy
//rhinoceros

//Test 17: Clear linked list. Contains 'jumps' = False
//

3.3 Stack<T> 和 Stack

Stack广泛的翻译是栈,是一种后进先出的集合。在一些特殊场景里,使用十分广泛。
Stack有两个很重要的方法Pop 和Push,出/进。Pop 获取最后一个元素,并退出栈,Push 向栈推入一个元素。
具体可以参照官方文档

4 集合相关命名空间

C# 的集合还有其他的一些命名空间里藏着宝贝,不过在实际开发中使用频率并不大,可以按需查看。

4.1 System.Collections.Concurrent 线程安全

这个命名空间,提供了一系列线程安全的集合类,当出现多线程操作集合的时候,应当使用这个命名空间的集合。名称和常用的类是一一对应的,不过只提供了ConcurrentDictionary<TKey,TValue>ConcurrentQueue<T>ConcurrentStack<T>等几个集合类。具体可以查看官方文档

4.2 System.Collections.Immutable 不可变集合

命名空间包含用于定义不可变集合的接口和类,如果需要使用这个命名空间,则需要使用NuGet下载。

    • 共享集合,使其使用者可以确保集合永远不会发生更改。
  • 提供多线程应用程序中的隐式线程安全(无需锁来访问集合)。
  • 遵循函数编程做法。
  • 在枚举过程中修改集合,同时确保该原始集合不会更改。
相关教程