.NETに定義されたGeneric型を利用しよう!

[C#] .NETに定義されたGeneric型を利用しよう!

※ 当サイトは広告を含みます。

ここでは.NETに定義されたジェネリック型を実際に利用してみましょう。
なお、利用することが目的なので、1つ1つのジェネリック型については深く解説しません。

System.Collections.Generic名前空間

コレクション系のジェネリック型が定義されてる空間です。C#でジェネリック型と言えば、ここです。
と言っても、ジェネリック型はあくまで総称なので、他の名前空間にも色々と定義されてます。

この名前空間の中にも複数のジェネリック型が存在しますが、今回はList型Dictionary型を使います。
数あるジェネリック型の中でも1番使うのがこれ。この2つを知ってれば概ね何とかなります。

List型

List型は可変長のコレクションを順番に管理するために使います。
リストと言えば、こんな感じの構造を想像すると思いますが、中身は可変長の配列です。

これに関しては深くは触れません。C#の仕様としてList型可変長配列(別名:動的配列)です。
C++で言うとvector型にあたります。ちなみに本当の意味でList型になってるのはLinkedList型です。

りさ
りさ

分かりづらいよ。

管理人
管理人

この命名はミスだろ。

使い方はこちら。コード内のコメントとか読んで参考にしてください。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      // new List<型>でインスタンス生成する
      var list = new System.Collections.Generic.List<int>();

      // Listにアイテムを追加する
      list.Add(1);
      list.Add(2);
      list.Add(3);
      list.Add(4);
      list.Add(5);

      // Listにforでアクセスする
      Console.WriteLine("----- for -----");
      for (int i = 0; i < list.Count; i++)
        Console.WriteLine($"list[{i}]={list[i]}");

      // Listの0番目を削除する
      list.RemoveAt(0);

      // Listの0番目に値を追加する
      list.Insert(0, 10);

      // Listにforでアクセスする
      Console.WriteLine("----- for -----");
      for (int i = 0; i < list.Count; i++)
        Console.WriteLine($"list[{i}]={list[i]}");

      // Listをソートする
      list.Sort();

      // Listにforでアクセスする
      Console.WriteLine("----- for -----");
      for (int i = 0; i < list.Count; i++)
        Console.WriteLine($"list[{i}]={list[i]}");

      // Listを逆順に並び替える
      list.Reverse();

      // Listにforでアクセスする
      Console.WriteLine("----- for -----");
      for (int i = 0; i < list.Count; i++)
        Console.WriteLine($"list[{i}]={list[i]}");

      // Listにforeachでアクセスする
      Console.WriteLine("----- foreach -----");
      foreach (var item in list)
        Console.WriteLine($"item={item}");

      // Listの中身を全て消す
      list.Clear();

      // Listにforeachでアクセスする
      Console.WriteLine("----- foreach -----");
      foreach (var item in list)
        Console.WriteLine($"item={item}");
    }
  }
}

公式ドキュメントhttps://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1

Dictionary型

Dictionary型はKeyValueの紐づけでコレクションを管理する動的配列です。

配列がインデックス経由でアクセスするのに対し、Dictionary型はKeyを利用します。
必ず1つのKeyに対して1つのValueが紐づき、絶対条件としてKeyの重複は許されません。

C#ではDictionary、または日本語で辞書と呼びますが、言語ごとに呼び名が異なります。
近い意味を持つのがAssociativeArray(連想配列)Map(マッピング配列)です。

管理人
管理人

言語間の仲が悪いので統一されてません。

りさ
りさ

もっと仲良くしてよ。

管理人
管理人

みんな自分が1番だと思ってるから無理。

また、インデックスとなるKeyは数値や文字列以外でもOK、基本的に何でもありなので順番の概念がありません。
加えてKeyの重複が禁止されてるので、同じKeyの登録を試みると例外が発生します。

肝心の使い方はこちら。KeyValueが両方ともジェネリック型になってるのがポイントです。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      // new Dictionary<Key,Value>でインスタンス生成する
      var dictionary = new System.Collections.Generic.Dictionary<string, int>();

      // Dictionaryにアイテムを追加する
      dictionary.Add("one", 1);
      dictionary.Add("two", 2);
      dictionary.Add("three", 3);

      // Dictionaryにforeachでアクセスする
      Console.WriteLine("----- foreach -----");
      foreach (var kv in dictionary)
        Console.WriteLine($"{{Key={kv.Key}, Value={kv.Value}}}");

      // DictionaryにKeyが入っているかチェックする
      if (dictionary.ContainsKey("zero"))
        Console.WriteLine("Keyが登録されてる");
      else
        Console.WriteLine("Keyが登録されてない");

      // Dictionaryに重複するKeyを登録する(例外発生)
      try
      {
        dictionary.Add("one", 1);
      }
      catch (Exception ex)
      {
        Console.WriteLine($"ex={ex.Message}");
      }

      // Dictionaryからアイテムの取得を試みる
      if (dictionary.TryGetValue("three", out var _value))
        Console.WriteLine($"Value={_value}");
      else
        Console.WriteLine("Keyが登録されてない");

      // Dictionaryにアイテムの登録を試みる
      if (dictionary.TryAdd("zero", 0))
        Console.WriteLine("登録に成功しました");
      else
        Console.WriteLine("既にKeyが存在します");

      // Dictionaryにアイテムの登録を試みる(重複)
      if (dictionary.TryAdd("zero", 0))
        Console.WriteLine("登録に成功しました");
      else
        Console.WriteLine("既にKeyが存在します");

      // Dictionaryにforeachでアクセスする
      Console.WriteLine("----- foreach -----");
      foreach (var kv in dictionary)
        Console.WriteLine($"{{Key={kv.Key}, Value={kv.Value}}}");

      // Dictionaryからアイテムを削除する
      dictionary.Remove("three");

      // Dictionaryにforeachでアクセスする
      Console.WriteLine("----- foreach -----");
      foreach (var kv in dictionary)
        Console.WriteLine($"{{Key={kv.Key}, Value={kv.Value}}}");
    }
  }
}

公式ドキュメントhttps://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2

他のジェネリック型

System.Collections.Genericに存在するジェネリック型(有名どころ)です。
興味ある人は個別のリンクから公式ドキュメントを読んでください。

管理人
管理人

データ構造はクラス名から察してください。

Generic名前空間

あんまり使わないのも含めて、全部を知りたい人向け。

公式ドキュメントhttps://learn.microsoft.com/en-us/dotnet/api/system.collections.generic

あとがき

.NETのジェネリック型は、配列の初期確保および不足時の追加確保の時、より大きなサイズを確保するように設計されてます。
仮に要素10個でも、実際のメモリ空間は100個(覚えてない)くらい確保され、要素数が少し増えても実際の領域は拡大してません。
これはメモリ空間的には無駄になりますが、現在のPC性能ならそうしたほうが処理が早く、1つ1つを追加で確保するより有利です。

管理人
管理人

そうだった気がします。

りさ
りさ

えっ?

管理人
管理人

たぶん...

◆ C#に関する学習コンテンツ

この記事は参考になりましたか?

関連記事

コメント

この記事へのコメントはありません。