C# ジェネリクス徹底解説:柔軟で型安全なコードを実現する
ジェネリクスを使用すると、クラスやメソッド内でプログラミング要素のデータ型の仕様を、実際にプログラムで使用されるまで遅延定義できます。つまり、ジェネリクスを使えば、あらゆるデータ型で動作するクラスやメソッドを記述できます。
クラスやメソッドの仕様を、データ型のプレースホルダ(型パラメータ)を使って記述します。コンパイラがそのクラスのコンストラクタやメソッドの呼び出しに遭遇すると、特定のデータ型を扱うコードを生成します。シンプルな例で概念を理解しましょう。
ライブ デモusing System;
using System.Collections.Generic;
namespace GenericApplication {
public class MyGenericArray<T> {
private T[] array;
public MyGenericArray(int size) {
array = new T[size + 1];
}
public T getItem(int index) {
return array[index];
}
public void setItem(int index, T value) {
array[index] = value;
}
}
class Tester {
static void Main(string[] args) {
// int 型の配列を宣言
MyGenericArray<int> intArray = new MyGenericArray<int>(5);
// 値を設定
for (int c = 0; c < 5; c++) {
intArray.setItem(c, c * 5);
}
// 値を取得
for (int c = 0; c < 5; c++) {
Console.Write(intArray.getItem(c) + " ");
}
Console.WriteLine();
// char 型の配列を宣言
MyGenericArray<char> charArray = new MyGenericArray<char>(5);
// 値を設定
for (int c = 0; c < 5; c++) {
charArray.setItem(c, (char)(c + 97));
}
// 値を取得
for (int c = 0; c < 5; c++) {
Console.Write(charArray.getItem(c) + " ");
}
Console.WriteLine();
Console.ReadKey();
}
}
}
上記のコードをコンパイルして実行すると、次の結果が得られます。
0 5 10 15 20 a b c d e
ジェネリクスの特徴
ジェネリクスは、以下の点でプログラムを強化します。
コードの再利用性、型安全性、パフォーマンスを最大化できます。
ジェネリック コレクション クラスを作成できます。.NET Framework クラス ライブラリには System.Collections.Generic 名前空間に新しいジェネリック コレクション クラスがいくつか含まれています。これらは System.Collections 名前空間のコレクション クラスの代わりに使用できます。
独自のジェネリック インターフェイス、クラス、メソッド、イベント、デリゲートを作成できます。
特定のデータ型のメソッドへのアクセスを可能にする制約を持つジェネリック クラスを作成できます。
リフレクションを使用して、実行時にジェネリック データ型で使用されている型情報を取得できます。
ジェネリック メソッド
前の例ではジェネリック クラスを使用しましたが、型パラメータを持つジェネリック メソッドを宣言することもできます。次のプログラムでこの概念を説明します。
ライブ デモusing System;
using System.Collections.Generic;
namespace GenericMethodAppl {
class Program {
static void Swap<T>(ref T lhs, ref T rhs) {
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
static void Main(string[] args) {
int a, b;
char c, d;
a = 10; b = 20;
c = 'I'; d = 'V';
// スワップ前の値を表示
Console.WriteLine("Int values before calling swap:");
Console.WriteLine("a = {0}, b = {1}", a, b);
Console.WriteLine("Char values before calling swap:");
Console.WriteLine("c = {0}, d = {1}", c, d);
// スワップを呼び出し
Swap<int>(ref a, ref b);
Swap<char>(ref c, ref d);
// スワップ後の値を表示
Console.WriteLine("Int values after calling swap:");
Console.WriteLine("a = {0}, b = {1}", a, b);
Console.WriteLine("Char values after calling swap:");
Console.WriteLine("c = {0}, d = {1}", c, d);
Console.ReadKey();
}
}
}
上記のコードをコンパイルして実行すると、次の結果が得られます。
Int values before calling swap: a = 10, b = 20 Char values before calling swap: c = I, d = V Int values after calling swap: a = 20, b = 10 Char values after calling swap: c = V, d = I
ジェネリック デリゲート
型パラメータを持つジェネリック デリゲートを定義できます。例:
delegate T NumberChanger<T>(T n);
次の例はこのデリゲートの使用方法を示しています。
ライブ デモusing System;
using System.Collections.Generic;
delegate T NumberChanger<T>(T n);
namespace GenericDelegateAppl {
class TestDelegate {
static int num = 10;
public static int AddNum(int p) {
num += p;
return num;
}
public static int MultNum(int q) {
num *= q;
return num;
}
public static int getNum() {
return num;
}
static void Main(string[] args) {
// デリゲート インスタンスを作成
NumberChanger<int> nc1 = new NumberChanger<int>(AddNum);
NumberChanger<int> nc2 = new NumberChanger<int>(MultNum);
// デリゲート オブジェクトを通じてメソッドを呼び出し
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
nc2(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
上記のコードをコンパイルして実行すると、次の結果が得られます。
Value of Num: 35 Value of Num: 175
C言語
- C# Hello World – 初めてのC#アプリケーション構築
- C# キーワードと識別子:ルール、一覧、ベストプラクティス完全ガイド
- C# 変数とプリミティブデータ型:完全マスターガイド
- C#演算子完全ガイド:C#における演算子の包括的解説
- C# ビット演算子とビットシフト演算子をマスターする:包括的ガイド
- C# 入出力の基礎:ユーザー入力と出力の基本をマスター
- C# の式、文、ブロック:実践例で徹底理解
- C# コメントをマスターする:種類、ベストプラクティス、XML ドキュメント
- C# switch 文をマスターする:構文、例、ベストプラクティス
- C# 三項演算子:条件式を簡潔に書くためのガイド
- C# break 文:使い方とタイミングを徹底解説