🧬 جادوی Generics در #C: نوشتن یک کد برای همه تایپها!
سیشارپ دو تا مکانیزم اصلی برای نوشتن کدهای قابل استفاده مجدد (reusable) داره: وراثت و جنریکها. وراثت این کار رو با یک تایپ پایه انجام میده، ولی جنریکها با یک "قالب" که شامل "نوعهای جایگزین" (placeholder) هست، این کار رو میکنن.
امروز میخوایم ببینیم جنریکها چی هستن و چرا به وجود اومدن.
1️⃣ مشکل چه بود؟ (چرا به جنریکها نیاز داریم؟)
فرض کنید به یه ساختار داده مثل پشته (Stack) نیاز داریم. بدون جنریکها، دو راه بد پیش روی ما بود:
راه حل اول: تکرار کد 👎
باید برای هر نوع دادهای که میخواستیم، یه کلاس جدا مینوشتیم (IntStack, StringStack, UserStack و...). این یعنی حجم وحشتناکی از کد تکراری.
راه حل دوم: استفاده از object 👎
میتونستیم یه ObjectStack بسازیم که هر نوعی رو قبول کنه (چون همه تایپها از object ارث میبرن). اما این روش دو تا مشکل بزرگ داشت که تو پست قبلی دیدیم:
• عدم ایمنی نوع (Type Safety): شما میتونستید به اشتباه یه string رو تو پشتهای که برای int ساخته بودید، Push کنید و کامپایلر هیچ خطایی نمیگرفت!
• هزینه پرفورمنس Boxing/Unboxing : برای کار با Value Typeها (مثل int)، باید مدام هزینه کپی کردن داده روی Heap (Boxing) و برگردوندنش (Unboxing) رو پرداخت میکردیم.
2️⃣ جنریکها (Generics): بهترینهای هر دو دنیا ✨
جنریکها دقیقاً برای حل این مشکل به وجود اومدن. به ما اجازه میدن یه "قالب" کد بنویسیم که هم قابل استفاده مجدد باشه (مثل ObjectStack) و هم ایمنی نوع و پرفورمنس بالا داشته باشه (مثل IntStack).
شما یک نوع جنریک با یک پارامتر T میسازید. بعداً موقع استفاده، به جای T، نوع داده واقعی خودتون رو قرار میدید.
public class Stack<T> // T یک نوع جایگزین است
{
int position;
T[] data = new T[100]; // آرایه ما حالا از نوع T است
public void Push(T obj) => data[position++] = obj;
public T Pop() => data[--position];
}
3️⃣ مزایای بزرگ در عمل
حالا ببینیم این نسخه جنریک چطور مشکلات رو حل میکنه:
var stack = new Stack<int>();
stack.Push(5);
stack.Push(10);
// stack.Push("hello"); // ❌ خطای زمان کامپایل! کامپایلر به شما ایمنی نوع کامل میده.
int x = stack.Pop(); // ✅ بدون نیاز به کست. بدون هزینه Unboxing. (x is 10)
int y = stack.Pop(); // ✅ (y is 5)
🤔 حرف حساب و تجربه شما
جنریکها یکی از قدرتمندترین قابلیتهای #C هستن و اساس تمام کالکشنهای مدرن داتنت (List<T>, Dictionary<TKey, TValue>) رو تشکیل میدن. تسلط بر اونها برای نوشتن کدهای قابل استفاده مجدد، امن و بهینه، ضروریه.
🔖 هشتگها:
#CSharp #DotNet #OOP #Generics





