Generics เพิ่มใน C# 2.0 เป็นแนวคิดสำคัญที่สุด ช่วยเขียนโค้ด Reusable, High-Performance, Type-Safe ตอน Compile-time ใช้ Type ในโค้ดโดยไม่ต้องรู้ Type ล่วงหน้า
Generics ใช้ทั่วไปใน .NET: Collections, Delegates, Async Code ไม่ต้องรู้ขนาด Collection ล่วงหน้า ใช้กับ Element Type ใดๆ รวมถึง Custom Types C# รองรับทั้ง Generic Types (Class, Interface ฯลฯ) และ Generic Methods
ใน Generics มี Type Parameters และ Type Arguments คล้าย Method ที่มี Parameters และ Arguments
Generic Types
Syntax: ชื่อ Type ตามด้วย Type Parameters ใน Angle Brackets เช่น Locator<T>
public class Locator<T> { }สร้าง Instance โดยระบุ Type Argument จริง:
var stringLocator = new Locator<string>();
ใช้ Type Parameter (T) ใน Method ของ Class:
public class Locator<T>
{
public IList<T> Items { get; set; }
public T Locate(int index) => Items[index];
}
var stringLocator = new Locator<string>();
string item = stringLocator.Locate(2);ประโยชน์เพิ่ม: IntelliSense ใน Editor จะแสดง Return Type เป็น string (ไม่ใช่ T) หาก Assign ให้ Type อื่น Compiler Error
// Error: Cannot convert 'string' to 'int' int item = stringLocator.Locate(2);
Generic Type ใช้ Type Parameter เป็น Type Argument เมื่อ繼承 Generic Base Type หรือ Interface:
public class LinkedList<T> : IEnumerable<T>
Generic Methods
Generic Method ประกาศ Type Parameter ใช้ภายใน Method และเป็น Parameter/Return Type เช่น Swap<T>:
public class Swapper
{
public T Swap<T>(ref T first, ref T second)
{
T temp = first;
first = second;
second = temp;
return temp;
}
}เรียกใช้ Generic Method ได้ Strongly Typed Variable:
var swapper = new Swapper(); int result = swapper.Swap<int>(ref a, ref b);
สามารถมี Multiple Generic Parameters ได้ เช่น Dictionary<TKey, TValue>
สิ่งที่สามารถเป็น Generic ได้:
- Types (ยกเว้น Enum): Class, Struct, Interface, Delegate
- Type Members: เฉพาะ Methods และ Nested Types
สิ่งที่ ไม่สามารถ เป็น Generic: Fields, Properties, Indexers, Constructors, Events, Finalizers
ตัวอย่างโค้ด
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var stringLocator = new Locator<string>()
{
Items = new string[] { "JavaScript", "CSharp", "Golang" }
};
Console.WriteLine(stringLocator.Locate(1)); // CSharp
var swapper = new Swapper();
int a = 5, b = 3;
int result = swapper.Swap<int>(ref a, ref b);
Console.WriteLine($"a = {a}, b = {b}"); // a = 3, b = 5
}
}
public class Locator<T>
{
public IList<T> Items { get; set; }
public T Locate(int index) => Items[index];
}
public class Swapper
{
public T Swap<T>(ref T first, ref T second)
{
T temp = first;
first = second;
second = temp;
return temp;
}
}ผลลัพธ์
CSharp a = 3, b = 5