🔬 نکات عمیق جنریکها: Static Data و مقدار default
در دو پست قبلی، با قیدها و وراثت در دنیای جنریکها آشنا شدیم. امروز در قسمت آخر این سری، به دو تا از نکات خیلی ظریف و فنی شیرجه میزنیم که رفتار جنریکها رو در سطح حافظه و مقادیر پیشفرض نشون میده.
این نکات، درک شما رو از جنریکها کامل میکنه.
1️⃣ مقدار پیشفرض T (default(T))
چطور میتونیم مقدار پیشفرض یک پارامتر جنریک T رو بدست بیاریم؟ چون T میتونه هر چیزی باشه (value type یا reference type)، ما نمیتونیم مستقیماً null یا 0 بهش بدیم.
راه حل #C، کلمه کلیدی default هست.
default(T)
به ما مقدار پیشفرض T رو میده:
🔹 اگه T یک Reference Type باشه، مقدارش null میشه.
🔹 اگه T یک Value Type باشه، مقدارش صفر میشه (نتیجه صفر کردن بیتهای حافظه).
static void Zap<T>(T[] array)
{
for (int i = 0; i < array.Length; i++)
{
// مقدار پیشفرض T را در آرایه قرار میدهد
array[i] = default(T);
}
}
// از #C 7.1 به بعد، میتونیم خلاصهتر بنویسیم:
// array[i] = default;
2️⃣ تلهی دادههای استاتیک در جنریکها ⚠️
این یکی از اون نکات خیلی مهمه که خیلیها رو غافلگیر میکنه.
قانون اینه: دادههای استاتیک (Static Fields/Properties) برای هر نوع بستهی جنریک (Closed Type)، منحصر به فرد و جداگانه هستن.
یعنی static فیلدِ <Bob<int هیچ ربطی به static فیلدِ <Bob<string نداره و هر کدوم در حافظه، جای خودشون رو دارن.
مثال کتاب برای درک بهتر این موضوع:
class Bob<T>
{
public static int Count;
}
// --- نتایج ---
Console.WriteLine(++Bob.Count); // خروجی: 1 (شمارنده مخصوص int)
Console.WriteLine(++Bob.Count); // خروجی: 2 (شمارنده مخصوص int)
Console.WriteLine(++Bob.Count); // خروجی: 1 (شمارنده مخصوص string، کاملاً جداست!)
Console.WriteLine(++Bob.Count); // خروجی: 1 (شمارنده مخصوص object، این هم جداست!)
🤔 حرف حساب و تجربه شما
این جزئیات فنی، نشون میده که جنریکها در #C فقط یه جایگزینی ساده متن نیستن، بلکه یه مکانیزم قدرتمند در سطح CLR هستن که تایپهای کاملاً جدیدی رو در زمان اجرا تولید میکنن.
🔖 هشتگها:
#CSharp #DotNet #OOP #Generics #AdvancedCSharp