C# Programming

Collectionコレクション

開発環境: Visual Studio 2003 

目次

  1. 目次
  2. コレクションって何?
  3. 汎用コレクション型
  4. ArrayList
  5. Queue
  6. Stack
  7. Hashtable

コレクションって何?

複数のオブジェクトを 1 つのグループにまとめたものです。
このようなコレクションはいろいろなケースで使いたくなるはずなので、使い方を覚えておくとわざわざ自分でクラスを作らずにすむので、便利。
どのようなコレクションを使えばよいのかは、MSのヘルプを参照してください。

汎用コレクション型

汎用コレクションには、次のような一般的な種類のデータ コレクションがあります。

汎用コレクション定義
Arraypublic abstract class Array : ICloneable, IList, ICollection, IEnumerable
ArrayListpublic class ArrayList : IList, ICollection, IEnumerable, ICloneable
Queuepublic class Queue : ICollection, IEnumerable, ICloneable
Stackpublic class Stack : ICollection, IEnumerable, ICloneable
Hashtablepublic class Hashtable : IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, ICloneable
SortedListpublic class SortedList : IDictionary, ICollection, IEnumerable, ICloneable

注意: スレッドセーフではない!

詳細は、MSのヘルプを参照してください。

コレクションのインスタンスは、基本的にスレッドセーフではありません。確実にスレッドセーフにするには、Synchronized メソッドで返されるラップされたインスタンスに対してオペレーションする必要があります。

コレクションのエニュメレーションは、ほかのスレッドがそのコレクションを変更する可能性があるため、本質的にスレッド セーフな処理ではありません。そのような場合には、例外が発生します。エニュメレーションを確実にスレッド セーフにするには、エニュメレーション中にコレクションをロックするか、例外をキャッチする必要があります。

ArrayList

この例では、MyObject という適当なクラスつくり、複数のインスタンスを ArrayList myArrayList に格納しています。
格納した各要素を foreach 、および MoveNext でアクセスしています。

foreach は、コレクション型をサポートしているので、foreach で各要素にアクセスできます。
また、GetEnumerator をサポートしているので、IEnumerator インターフェースの MoveNext()メソッドでも各要素にアクセスできます。
using System;
using System.Collections;

namespace ArrayList
{
        /// <summary>
        /// Class1 の概要の説明です。
        /// </summary>
        class Class1
        {
                /// <summary>
                /// ArrayList に入れるクラス定義
                /// </summary>
                public class MyObject
                {
                        public int x;
                        public int y;
                        public string str;
                        public MyObject(int xx, int yy, string s)
                        {
                                x = xx;
                                y = yy;
                                str = s;
                        }
                }

                /// <summary>
                /// アプリケーションのメイン エントリ ポイントです。
                /// </summary>
                [STAThread]
                static void Main(string[] args)
                {
                        System.Collections.ArrayList myArrayList = new System.Collections.ArrayList();

                        myArrayList.Add(new MyObject(1,2, "Hello"));
                        myArrayList.Add(new MyObject(22,33, "World"));
                        myArrayList.Add(new MyObject(333,444, "Hello World"));

                        foreach(MyObject myObj in myArrayList)
                        {
                                Console.WriteLine( "{0}, {1}, {2}", myObj.x, myObj.y, myObj.str);
                        }

                        // IEnumerator を使ってアクセスできる。
                        System.Collections.IEnumerator myEnumerator = myArrayList.GetEnumerator();
                        while ( myEnumerator.MoveNext() )
                                Console.WriteLine( "{0}, {1}, {2}", 
                                        ((MyObject)myEnumerator.Current).x, 
                                        ((MyObject)myEnumerator.Current).y,
                                        ((MyObject)myEnumerator.Current).str );
                        Console.ReadLine();
                }
        }
}

結果は、このようになります。
Image

Queue

この例では、MyObject という適当なクラスつくり、複数のインスタンスを Queue.Enqueue()で格納しています。
Queue.Dequeue() でQueue から取り出せます。

また、GetEnumerator をサポートしているので、IEnumerator インターフェースの MoveNext()メソッドでも各要素にアクセスできます。
using System;
using System.Collections;

namespace Queue
{
        /// <summary>
        /// Class1 の概要の説明です。
        /// </summary>
        class Class1
        {
                /// <summary>
                /// ArrayList に入れるクラス定義
                /// </summary>
                public class MyObject
                {
                        public int x;
                        public int y;
                        public string str;
                        public MyObject(int xx, int yy, string s)
                        {
                                x = xx;
                                y = yy;
                                str = s;
                        }
                }

                /// <summary>
                /// アプリケーションのメイン エントリ ポイントです。
                /// </summary>
                [STAThread]
                static void Main(string[] args)
                {
                        System.Collections.Queue myQueue = new System.Collections.Queue();

                        myQueue.Enqueue(new MyObject(1,2, "Hello"));
                        myQueue.Enqueue(new MyObject(22,33, "World"));
                        myQueue.Enqueue(new MyObject(333,444, "Hello World"));

                        MyObject myObj = null;

                        myObj = (MyObject)myQueue.Dequeue();
                        Console.WriteLine( "{0}, {1}, {2}", myObj.x, myObj.y, myObj.str);

                        myObj = (MyObject)myQueue.Dequeue();
                        Console.WriteLine( "{0}, {1}, {2}", myObj.x, myObj.y, myObj.str);

                        myObj = (MyObject)myQueue.Dequeue();
                        Console.WriteLine( "{0}, {1}, {2}", myObj.x, myObj.y, myObj.str);
                        
                        Console.WriteLine();

                        PrintValues(myQueue);
                        Console.ReadLine();
                }

                // IEnumerator を使ってアクセスできる。
                public static void PrintValues( IEnumerable myCollection )  
                {
                        System.Collections.IEnumerator myEnumerator = myCollection.GetEnumerator();
                        while ( myEnumerator.MoveNext() )
                        {
                                MyObject myObj = (MyObject)myEnumerator.Current;
                                Console.WriteLine( "{0}, {1}, {2}", myObj.x, myObj.y, myObj.str);
                                Console.WriteLine();
                        }
                }               
        }
}
Queue なので、FIFO になります。したがって、結果はキューに入れたとおりの順番で出力されます。
また、データを Dequeue でキューから取り除きますから、それぞれ1回づつプリントされることになります。
Image

Stack

この例では、MyObject という適当なクラスつくり、複数のインスタンスを Stack.Push()で格納しています。
Stack.Pop() で Stack から取り出せます。
また、Stack.Peek() で、Stack から取り除くことなくオブジェクトを取得することができます。

また、GetEnumerator をサポートしているので、IEnumerator インターフェースの MoveNext()メソッドでも各要素にアクセスできます。
using System;
using System.Collections;

namespace Stack
{
        /// <summary>
        /// Class1 の概要の説明です。
        /// </summary>
        class Class1
        {
                /// <summary>
                /// ArrayList に入れるクラス定義
                /// </summary>
                public class MyObject
                {
                        public int x;
                        public int y;
                        public string str;
                        public MyObject(int xx, int yy, string s)
                        {
                                x = xx;
                                y = yy;
                                str = s;
                        }
                }

                /// <summary>
                /// アプリケーションのメイン エントリ ポイントです。
                /// </summary>
                [STAThread]
                static void Main(string[] args)
                {
                        System.Collections.Stack myStack = new System.Collections.Stack();

                        myStack.Push(new MyObject(1,2, "First"));
                        myStack.Push(new MyObject(22,33, "Second"));
                        myStack.Push(new MyObject(333,444, "Third"));

                        MyObject myObj = null;

                        myObj = (MyObject)myStack.Pop();
                        Console.WriteLine( "{0}, {1}, {2}", myObj.x, myObj.y, myObj.str);

                        myObj = (MyObject)myStack.Pop();
                        Console.WriteLine( "{0}, {1}, {2}", myObj.x, myObj.y, myObj.str);

                        myObj = (MyObject)myStack.Peek();
                        Console.WriteLine( "{0}, {1}, {2}", myObj.x, myObj.y, myObj.str);
                        
                        Console.WriteLine();

                        myStack.Push(new MyObject(4444,5555, "Fourth"));
                        PrintValues(myStack);
                        Console.ReadLine();
                }

                // IEnumerator を使ってアクセスできる。
                public static void PrintValues( IEnumerable myCollection )  
                {
                        System.Collections.IEnumerator myEnumerator = myCollection.GetEnumerator();
                        while ( myEnumerator.MoveNext() )
                        {
                                MyObject myObj = (MyObject)myEnumerator.Current;
                                Console.WriteLine( "{0}, {1}, {2}", myObj.x, myObj.y, myObj.str);
                        }
                }               
        }
}
この例では Stack なので、FILO になります。したがって、結果はスタックに入れた時の逆順で出力されます。
また、データを Dequeue でキューから取り除きますから、それぞれ1回づつプリントされることになります。
ただし、この例では 1,2,First の時に Peek () で Stack から取り除いてないので、1,2,First は2回プリントされています。Image

Hashtable

この例では、Key と Value のオブジェクトのペアを myHashTable.Add(Key, Value)で格納しています。
hashtable["Key"] で、Key, Value ペアの Value を取り出すことができます。

また、GetEnumerator をサポートしているので、IEnumerator インターフェースの MoveNext()メソッドでも各要素にアクセスできます。
using System;
using System.Collections;

namespace Hashtable
{
        /// <summary>
        /// Class1 の概要の説明です。
        /// </summary>
        class Class1
        {
                /// <summary>
                /// アプリケーションのメイン エントリ ポイントです。
                /// </summary>
                [STAThread]
                static void Main(string[] args)
                {
                        System.Collections.Hashtable myHashTable = 
			new System.Collections.Hashtable();

                        myHashTable.Add("Second", 2);
                        myHashTable.Add("First", 1);
                        myHashTable.Add("Third", 3);

                        Console.WriteLine( "{0}, {1}", "First", myHashTable["First"]);
                        Console.WriteLine( "{0}, {1}", "Second", myHashTable["Second"]);
                        Console.WriteLine( "{0}, {1}", "Third", myHashTable["Third"]);
        
                        Console.WriteLine();

                        PrintValues(myHashTable);
                        Console.ReadLine();
                }

                // IEnumerator を使ってアクセスできる。
                public static void PrintValues( System.Collections.Hashtable myHashTab )  
                {
                        System.Collections.IDictionaryEnumerator myEnumerator = 
                        	myHashTab.GetEnumerator();
                        while ( myEnumerator.MoveNext() )
                        {
                                Console.WriteLine( "{0}, {1}", 
				myEnumerator.Key, myEnumerator.Value);
                        }
                }               
        }
}
この例では"Key"に一致するものを取得することができます。したがって、結果は指定した順番で出力することができます。
最初の3つは、First, Second, Third の順番に取り出したもので、その順番になっています。
次の3つは、MoveNext() で取り出したものなので、順番は 2,1,3 で入れたにもかかわらず、3,2,1 の順で出力されています。
これは、"Key" のハッシュ値でハッシュテーブルに格納されている(はず)なので、入力順番に出力されるとは限らない。

Image