ここでは.NETに定義されたジェネリック型を実際に利用してみましょう。
なお、利用することが目的なので、1つ1つのジェネリック型については深く解説しません。
ここではC#のジェネリックを学習します。もしくはジェネリック型と呼びます。また、C++だとテンプレートと呼ばれ、機能的にはC#よりも優れてます。ジェネリック(generic)ジェネリックとは、汎用的な型を利用してメソッドやクラスの処理を共通化する機能です。そして、この時に利用する型をジェネリック型(generic type)と言います。Genericは英語で汎用とか一般を意味します(たぶん)。汎用的に使える型って意味ですか?そうだよ(適当)。雑.....
System.Collections.Generic名前空間
コレクション系のジェネリック型が定義されてる空間です。C#でジェネリック型と言えば、ここです。
と言っても、ジェネリック型はあくまで総称なので、他の名前空間にも色々と定義されてます。
この名前空間の中にも複数のジェネリック型が存在しますが、今回はList型とDictionary型を使います。
数あるジェネリック型の中でも1番使うのがこれ。この2つを知ってれば概ね何とかなります。
List型
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型はKeyとValueの紐づけでコレクションを管理する動的配列です。
配列がインデックス経由でアクセスするのに対し、Dictionary型はKeyを利用します。
必ず1つのKeyに対して1つのValueが紐づき、絶対条件としてKeyの重複は許されません。
C#ではDictionary、または日本語で辞書と呼びますが、言語ごとに呼び名が異なります。
近い意味を持つのがAssociativeArray(連想配列)やMap(マッピング配列)です。
プログラムで利用する便利な配列、これをコンピュータサイエンスの視点から理解しましょう。汎用的な知識を得ることで、効率のいいコードが書けたり、別のプログラミング言語を学ぶ時の役に立ちます。配列 (array) の概念配列は変数の集合です。例えばユーザー4人の年齢を管理する場合、変数を4つ用意しても実現できますが、それでは使い勝手が悪いです。なので1つだけ変数を作ってアドレス値を管理、そのアドレス値を起点に複数個のデータを管理するのが配列です。配列とメモリの関係変数と...
言語間の仲が悪いので統一されてません。
もっと仲良くしてよ。
みんな自分が1番だと思ってるから無理。
また、インデックスとなるKeyは数値や文字列以外でもOK、基本的に何でもありなので順番の概念がありません。
加えてKeyの重複が禁止されてるので、同じKeyの登録を試みると例外が発生します。
肝心の使い方はこちら。KeyとValueが両方ともジェネリック型になってるのがポイントです。
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#に関する学習コンテンツ
この記事は参考になりましたか?
コメント