ASEホーム サイトマップ 交通アクセス お問い合わせ chineese english
             
                                          
最近の技術情報  一覧

                 
 


                 
 


                 
 


                 
 


                 
 


                 
 


                 
 


                 
 


                 
 


                 
 


                 
 


 
トップページ > 技術情報

.NET Framework を理解する(第2回)

2009年10月28日

.NET
 

.NET Framework のデータ構造

 

Stack , Heap , Hash どれも開発者にはなじみのデータ構造です。
もちろん、必要な場合はいくらでもあるでしょう。そんなとき皆さんは「自作するんですか?」
.NET には始めからデータ構造を容易に使えるように、実装されています。
車輪の再開発は是非やめてください!



Collection のことはじめ

 

.NET Framework には、System.Collections 名前空間があり、ここには様々なデータ構造が既に実装されています。
どんなものがあるか、以下に並べてみます。


基本のコレクション
クラス代表的なメソッド
ArrayListAdd, Insert, Remove, RemoveAt, Clear 等
BitArraySet, Get, SetAll, And, Or, Not, Xor 等
HashtableAdd, Clear, Remove 等
QueueEnqueue, Dequeue, Peek 等
SortedListAdd, Clear, Remove, RemoveAt 等
StackPush, Pop, Peek 等


これらのクラスは、全て内部的に object で格納し、object で取得します。
様々な型を保持出来る反面、型安全性はありません。


型安全を得る為に、厳密な型を指定したコレクションを実装する為の基底クラスも存在します。


ユーザ実装コレクション用基底クラス
クラス
CollectionBase
DictionaryBase
ReadOnlyCollectionBase


これらは、通常のデータ構造同様に扱う事が出来ますが、 それ以外にも配列のようなキーによるインデックスアクセス、foreach による列挙等をサポートします。



スレッドセーフ

 

上記のデータ構造は、もはや枯れたものばかりです。
foreach の利用等のメリットを捨ててしまえば、車輪の再開発でもさほど苦にはならないでしょう。
しかし、マルチスレッドを考慮すると、とたんに話は変わります。
昨今、CPU のマルチコア化が進み、4 コア 8 スレッドも当たり前になりつつあります。
今後、マルチスレッド化の波が押し寄せてくる事でしょう。少なくとも Microsoft はそう信じて .NET4.0 を拡張しています。


では、あなたが再開発した車輪は、マルチスレッドで正常に扱えますか?


ここが非常にバグの温床になります。
しかし、.NET では一工夫でスレッドセーフなコレクションインスタンスを作成することができます。


ArrayList safeList
    = ArrayList.Synchronized(new ArrayList());

これだけで safeList はスレッドセーフになりました。
「同期オブジェクトの取得して、、、」等考えなくても大丈夫なのです。



型安全

 

上記で述べた通り、デフォルトのコレクションに型安全はありません。
これがどういう事かといいますと、以下のような事起こることがあります。


ArrayList list = new ArrayList();

// 文字列を追加していきますが
list.Add("ASE");
list.Add("AdvancedSoft...");

// 突然数値を入れる事ができます
list.Add(2009);

// object で代入し、object で取得します。
foreach(object obj in list)
{
    // 中に int 値が入っているので、実行時例外発生
    string name = (string)obj;
    Console.WriteLine("Hello" + name);
}

仮に、コレクションクラスをメソッドの引数で渡すとしたり、何らかのメソッドの返値がコレクション型だとして、中に何が入っているのでしょうか? これは取り出してみないと型が分からないのです。



型安全を持ったコレクションを実装する為の、基底クラスは存在するものの、正直便利とは言いがたいでしょう。



型安全とジェネリック

 

.NET Framework2.0 以降では、ジェネリッククラスをサポートしています。
これは、主にコレクション等で利用され、特定のデータ型に固有ではない操作をカプセル化します。


説明では分かりづらいでしょうから、実際にジェネリッククラスを利用してみます。


System.Collections.Generic.List<string> list
    = new System.Collections.Generic.List<string>();
list.Add("ASE");

// 次の行は、string 指定したジェネリッククラスに
// 整数型を代入出来ないため、コンパイルエラーになります。
// list.Add(11);

// list には string しか入っていない事が保証されるので、
// object からのキャストが不要です。
string value = list[0];

このように、ジェネリックを利用することで、型安全を得る事ができます。



ジェネリックの制約

 

独自のジェネリッククラスを作成するにあたり、制約を課すことができます。


public abstract class License
{
    public string Name
    {
        get;
        set;
    }
    
    public virtual string[] Questions()
    {
        // 試験問題等
    }
}

public class ComputerLicense : License
{
    // 何らかの実装
}

public class SportsLicense : License
{
    // 何らかの実装
}

// 資格試験を行う部屋は無数にあれど、
// 何の資格かは部屋(インスタンス)によって違う場合など
public class ExaminationRoom<T> where T :  License
{
    T license;
    public ExaminationRoom(T targetLicense)
    {
        license = targetLicense;
    }
    
    public bool Exam()
    {
        // T は License 型である事が保証されるので、
        // Questions メソッドが存在する。
        string[] questionArr = license.Questions();
        
        /* 試験の実行など */
    }
}

class Program
{
    static void Main(string[] args)
    {
        ExaminationRoom<ComputerLicense> room
            = new ExaminationRoom<ComputerLicense>(
                new ComputerLicense());
        if(room.Exam())
        {
            // 合格時の処理など
        }
        
        /*
        // 以下のコードは、コンパイルエラーになります。
        ExaminationRoom<string> room
            = new ExaminationRoom<string>(
                "SampleError");
         */
    }
}

このような制約を利用すれば、コレクションのようなデータ構造に限らず、プログラムの設計にも有用です。
制約には他に、以下のようなものがあります。


制約と意味
制約構文制約内容
where T : [interface][interface]を実装する
where T : [class][class]かそのサブクラス
where T : new()引数なしのコンストラクタを持つ
where T : class参照型の指定
where T : struct構造体指定


ジェネリックコレクション

 

ジェネリック機能を利用する事で、非常に容易かつ、 コレクションに比べて高速な動作をするジェネリックコレクションが、.NET Framework2.0 より実装されました。


このコレクションは、System.Collections.Generic 名前空間に宣言されていて、通常の場合、こちらを利用する方がよいでしょう。


主なクラスは以下の通りです。


System.Collections.Generic
クラス対応する System.Collections クラス
ListArrayList
DictionaryHashtable
QueueQueue
SortedListSortedList
StackStack
LinkedListなし。双方向の連結リストです。
SortedDictionaryなし。ソートされたキー/値ペアのコレクションです。

ジェネリックの実装方法の違いに起因するものですが、.NET1.1 以下の .NET Framework と互換性はありません。


次回は、スレッドや同期制御といった話題に目を向けてみたいと思います。





関連するエントリー

 
 
現在ページの上部へ戻る