📖 سری آموزشی کتاب C# 12 in a Nutshell
دروازههای هوشمند کلاس شما چرا تو کدنویسی حرفهای، تقریباً هیچوقت فیلدهای یه کلاس رو public نمیکنن؟ چون این کار یعنی از دست دادن کنترل! هر کسی از بیرون میتونه هر مقدار نامعتبری رو توش بریزه.
راه حل #C برای این مشکل، یه قابلیت فوقالعاده به اسم پراپرتی (Property) هست.
پراپرتیها از بیرون شبیه فیلدهای معمولی به نظر میرسن و به همون سادگی استفاده میشن، ولی در داخل، در واقع متدهای خاصی هستن که بهشون اکسسور (accessor) گفته میشه. این به ما کنترل کامل روی خوندن و نوشتن مقدار رو میده.
در رایجترین حالت، یک پراپرتی از دو بخش تشکیل شده:
• فیلد پشتیبان (Backing Field): یک فیلد private که داده واقعی رو نگه میداره.
• پراپرتی public: دروازهای که به دنیای بیرون اجازه دسترسی کنترلشده به اون فیلد رو میده.
✨️این پراپرتی، دو اکسسور داره:
🔹️get:
وقتی پراپرتی رو میخونیم، این بلوک اجرا میشه.
🔹️set:
وقتی مقداری رو به پراپرتی اختصاص میدیم، این بلوک اجرا میشه. کلمه کلیدی value در اینجا، به مقداری که داره ست میشه، اشاره داره.
جادوی پراپرتیها اینجاست که میتونید تو اکسسورهای get و set، منطق دلخواهتون رو پیاده کنید. مثلاً اعتبارسنجی (validation).
🤔 حرف حساب و قانون طلایی
قانون طلایی شیءگرایی: فیلدها رو همیشه private نگه دارید و با پراپرتیهای public اونها رو در معرض دید بذارید. این کار به شما کنترل کامل روی کلاسهاتون میده و اساس کپسولهسازیه.
🏦 پراپرتیها (Properties) در #C:
دروازههای هوشمند کلاس شما چرا تو کدنویسی حرفهای، تقریباً هیچوقت فیلدهای یه کلاس رو public نمیکنن؟ چون این کار یعنی از دست دادن کنترل! هر کسی از بیرون میتونه هر مقدار نامعتبری رو توش بریزه.
راه حل #C برای این مشکل، یه قابلیت فوقالعاده به اسم پراپرتی (Property) هست.
1️⃣ پراپرتی چیست؟ فیلد با ماسک متد! 🎭
پراپرتیها از بیرون شبیه فیلدهای معمولی به نظر میرسن و به همون سادگی استفاده میشن، ولی در داخل، در واقع متدهای خاصی هستن که بهشون اکسسور (accessor) گفته میشه. این به ما کنترل کامل روی خوندن و نوشتن مقدار رو میده.
Stock msft = new Stock();
msft.CurrentPrice = 30; // اکسسور set صدا زده میشه
msft.CurrentPrice -= 3;
Console.WriteLine(msft.CurrentPrice); // اکسسور get صدا زده میشه
2️⃣ کالبدشکافی یک پراپرتی 🔬
در رایجترین حالت، یک پراپرتی از دو بخش تشکیل شده:
• فیلد پشتیبان (Backing Field): یک فیلد private که داده واقعی رو نگه میداره.
• پراپرتی public: دروازهای که به دنیای بیرون اجازه دسترسی کنترلشده به اون فیلد رو میده.
✨️این پراپرتی، دو اکسسور داره:
🔹️get:
وقتی پراپرتی رو میخونیم، این بلوک اجرا میشه.
🔹️set:
وقتی مقداری رو به پراپرتی اختصاص میدیم، این بلوک اجرا میشه. کلمه کلیدی value در اینجا، به مقداری که داره ست میشه، اشاره داره.
public class Stock
{
// ۱. فیلد پشتیبان (private)
private decimal _currentPrice;
// ۲. پراپرتی عمومی (public)
public decimal CurrentPrice
{
get { return _currentPrice; }
set { _currentPrice = value; }
}
}
3️⃣ قدرت واقعی: کپسولهسازی (Encapsulation) 🛡
جادوی پراپرتیها اینجاست که میتونید تو اکسسورهای get و set، منطق دلخواهتون رو پیاده کنید. مثلاً اعتبارسنجی (validation).
public class Stock
{
private decimal _currentPrice;
public decimal CurrentPrice
{
get { return _currentPrice; }
set
{
// منطق اعتبارسنجی
if (value < 0)
{
throw new ArgumentException("Price cannot be negative!");
}
_currentPrice = value;
}
}
}
🤔 حرف حساب و قانون طلایی
قانون طلایی شیءگرایی: فیلدها رو همیشه private نگه دارید و با پراپرتیهای public اونها رو در معرض دید بذارید. این کار به شما کنترل کامل روی کلاسهاتون میده و اساس کپسولهسازیه.
🔖 هشتگها:
#CSharp #Programming #DotNet #OOP #Properties #Encapsulation
📖 سری آموزشی کتاب C# 12 in a Nutshell
در برنامهنویسی شیءگرا، کپسولهسازی (Encapsulation) یعنی مخفی کردن جزئیات پیادهسازی و فقط نمایش دادن چیزهای ضروری. ابزار اصلی ما برای این کار در C# Access Modifiers هست.
این کلمات کلیدی، نگهبانان کد شما هستن و مشخص میکنن که هر کلاس یا عضو اون، از کجا قابل دسترسیه.
معرفی نگهبانان
دربهای کاملاً باز! هر کسی از هر جایی (چه داخل اسمبلی و چه بیرون) میتونه ببینه و استفاده کنه.
فقط خودیها! فقط کدهای داخل همون اسمبلی (پروژه) میتونن ببینن. این حالت پیشفرض برای کلاسهای غیر تودرتو است.
راز شخصی! فقط کدهای داخل همون کلاس یا struct میتونن ببینن. این حالت پیشفرض برای اعضای کلاسها (مثل فیلدها و متدها) هست.
فقط خانواده! فقط کدهای داخل همون کلاس و کلاسهای فرزندی که ازش ارثبری کردن، میتونن ببینن.
خودیها و خانواده! اجتماع protected و internal. یعنی هم از داخل اسمبلی جاری دیده میشه و هم توسط کلاسهای فرزند (حتی اگه تو یه اسمبلی دیگه باشن).
فقط خانوادهی خودی! اشتراک protected و internal. یعنی فقط توسط کلاسهای فرزندی که در همون اسمبلی هستن، دیده میشه. این سطح دسترسی از protected و internal به تنهایی، محدودتره.
فقط همین فایل! اعضایی که با file مشخص میشن، فقط در همون فایلی که تعریف شدن، قابل مشاهده هستن. این بیشتر برای Source Generatorها کاربرد داره.
نکات حرفهای (Pro Tips) 💡
Friend Assemblies:
گاهی وقتا میخواید به یه پروژه دیگه (مثل پروژه تست) اجازه بدید که به اعضای internal شما دسترسی داشته باشه. با اتریبیوت [assembly: InternalsVisibleTo("FriendAssemblyName")] در فایل AssemblyInfo.cs یا .csproj میتونید این کار رو انجام بدید.
Accessibility Capping (سقف دسترسی):
سطح دسترسی یک تایپ، سطح دسترسی اعضای public اون رو محدود میکنه. یعنی یه متد public داخل یه کلاس internal، در عمل internal حساب میشه.
انتخاب درست Access Modifier، یکی از مهمترین تصمیمها در طراحی APIهای تمیز و قابل نگهداریه.
🛡راهنمای کامل Access Modifiers در #C: چه کسی کد شما را میبیند؟
در برنامهنویسی شیءگرا، کپسولهسازی (Encapsulation) یعنی مخفی کردن جزئیات پیادهسازی و فقط نمایش دادن چیزهای ضروری. ابزار اصلی ما برای این کار در C# Access Modifiers هست.
این کلمات کلیدی، نگهبانان کد شما هستن و مشخص میکنن که هر کلاس یا عضو اون، از کجا قابل دسترسیه.
معرفی نگهبانان
🌍 public (عمومی):
دربهای کاملاً باز! هر کسی از هر جایی (چه داخل اسمبلی و چه بیرون) میتونه ببینه و استفاده کنه.
🏢 internal (داخلی):
فقط خودیها! فقط کدهای داخل همون اسمبلی (پروژه) میتونن ببینن. این حالت پیشفرض برای کلاسهای غیر تودرتو است.
🔐 private (خصوصی):
راز شخصی! فقط کدهای داخل همون کلاس یا struct میتونن ببینن. این حالت پیشفرض برای اعضای کلاسها (مثل فیلدها و متدها) هست.
👨👩👧 protected (محافظت شده):
فقط خانواده! فقط کدهای داخل همون کلاس و کلاسهای فرزندی که ازش ارثبری کردن، میتونن ببینن.
🤝 protected internal:
خودیها و خانواده! اجتماع protected و internal. یعنی هم از داخل اسمبلی جاری دیده میشه و هم توسط کلاسهای فرزند (حتی اگه تو یه اسمبلی دیگه باشن).
🤫 private protected:
فقط خانوادهی خودی! اشتراک protected و internal. یعنی فقط توسط کلاسهای فرزندی که در همون اسمبلی هستن، دیده میشه. این سطح دسترسی از protected و internal به تنهایی، محدودتره.
📄 file (از C# 11):
فقط همین فایل! اعضایی که با file مشخص میشن، فقط در همون فایلی که تعریف شدن، قابل مشاهده هستن. این بیشتر برای Source Generatorها کاربرد داره.
نکات حرفهای (Pro Tips) 💡
Friend Assemblies:
گاهی وقتا میخواید به یه پروژه دیگه (مثل پروژه تست) اجازه بدید که به اعضای internal شما دسترسی داشته باشه. با اتریبیوت [assembly: InternalsVisibleTo("FriendAssemblyName")] در فایل AssemblyInfo.cs یا .csproj میتونید این کار رو انجام بدید.
Accessibility Capping (سقف دسترسی):
سطح دسترسی یک تایپ، سطح دسترسی اعضای public اون رو محدود میکنه. یعنی یه متد public داخل یه کلاس internal، در عمل internal حساب میشه.
🤔 حرف حساب و تجربه شما
انتخاب درست Access Modifier، یکی از مهمترین تصمیمها در طراحی APIهای تمیز و قابل نگهداریه.
🔖 هشتگها:
#OOP #Encapsulation
📖 سری آموزشی کتاب C# 12 in a Nutshell
تا حالا شده یه کلاسی بنویسید که اونقدر به یه کلاس دیگه وابسته باشه که انگار باید جزئی از اون باشه؟ یا بخواید یه کلاس کمکی بسازید که فقط و فقط توسط یک کلاس دیگه استفاده میشه؟
سیشارپ برای این سناریوها یه راه حل خیلی تمیز و قدرتمند داره: Nested Types (تایپهای تودرتو).
یه Nested Type، یک تایپ (class, struct, enum, ...) است که داخل یک کلاس یا struct دیگه تعریف میشه. مثل یه جعبهی کوچیک، داخل یه جعبهی بزرگتر.
برای دسترسی به یک Nested Type از بیرون، باید اون رو با اسم کلاس بیرونی مشخص کنید:
چرا باید از یه Nested Type استفاده کنیم؟ چون چند تا قدرت ویژه دارن که کلاسهای معمولی ندارن:
مهمترین قدرتشون اینه که میتونن به اعضای private و protected کلاسی که داخلش هستن، دسترسی داشته باشن! این یعنی یه سطح کپسولهسازی فوقالعاده.
میتونن هر Access Modifierی داشته باشن (public, private, protected و...). این در حالیه که کلاسهای معمولی فقط میتونن public یا internal باشن. پیشفرض دسترسی برای Nested Typeها، private هست.
این مهمترین بخش ماجراست.
❌ دلیل اشتباه: استفاده از Nested Type برای جلوگیری از شلوغ شدن namespace. برای این کار از namespace تودرتو استفاده کنید.
✅ دلایل درست: فقط زمانی از Nested Type استفاده کنید که:
• کلاس داخلی شما به شدت به کلاس بیرونی وابسته است و به اعضای private اون نیاز مستقیم داره.
• میخواید با استفاده از Access Modifierها (مثل private یا protected)، اون کلاس رو از دنیای بیرون کاملاً مخفی کنید و به عنوان یه جزئیات پیادهسازی داخلی نگهش دارید.
Nested Types
یه ابزار قدرتمند برای کپسولهسازی پیشرفته هستن، به شرطی که به جا و درست ازشون استفاده بشه.
📦 کلاس در کلاس: راهنمای کامل Nested Types در #C
تا حالا شده یه کلاسی بنویسید که اونقدر به یه کلاس دیگه وابسته باشه که انگار باید جزئی از اون باشه؟ یا بخواید یه کلاس کمکی بسازید که فقط و فقط توسط یک کلاس دیگه استفاده میشه؟
سیشارپ برای این سناریوها یه راه حل خیلی تمیز و قدرتمند داره: Nested Types (تایپهای تودرتو).
1️⃣ Nested Type چیست؟
یه Nested Type، یک تایپ (class, struct, enum, ...) است که داخل یک کلاس یا struct دیگه تعریف میشه. مثل یه جعبهی کوچیک، داخل یه جعبهی بزرگتر.
public class TopLevel
{
public class Nested { } // کلاس تودرتو
public enum Color { Red, Blue, Tan } // enum تودرتو
}
برای دسترسی به یک Nested Type از بیرون، باید اون رو با اسم کلاس بیرونی مشخص کنید:
TopLevel.Nested n = new TopLevel.Nested();
TopLevel.Color color = TopLevel.Color.Red;
2️⃣ ابرقدرتهای Nested Types 🦸♂️
چرا باید از یه Nested Type استفاده کنیم؟ چون چند تا قدرت ویژه دارن که کلاسهای معمولی ندارن:
دسترسی به اعضای private: 🔐
مهمترین قدرتشون اینه که میتونن به اعضای private و protected کلاسی که داخلش هستن، دسترسی داشته باشن! این یعنی یه سطح کپسولهسازی فوقالعاده.
public class TopLevel
{
private static int x = 10;
class Nested
{
// Nested به فیلد private کلاس TopLevel دسترسی داره!
static void Foo() => Console.WriteLine(TopLevel.x);
}
}
سطوح دسترسی بیشتر: 🛡
میتونن هر Access Modifierی داشته باشن (public, private, protected و...). این در حالیه که کلاسهای معمولی فقط میتونن public یا internal باشن. پیشفرض دسترسی برای Nested Typeها، private هست.
3️⃣ قانون طلایی: کی از Nested Type استفاده کنیم؟ 🎯
این مهمترین بخش ماجراست.
❌ دلیل اشتباه: استفاده از Nested Type برای جلوگیری از شلوغ شدن namespace. برای این کار از namespace تودرتو استفاده کنید.
✅ دلایل درست: فقط زمانی از Nested Type استفاده کنید که:
• کلاس داخلی شما به شدت به کلاس بیرونی وابسته است و به اعضای private اون نیاز مستقیم داره.
• میخواید با استفاده از Access Modifierها (مثل private یا protected)، اون کلاس رو از دنیای بیرون کاملاً مخفی کنید و به عنوان یه جزئیات پیادهسازی داخلی نگهش دارید.
🤔 حرف حساب و تجربه شما
Nested Types
یه ابزار قدرتمند برای کپسولهسازی پیشرفته هستن، به شرطی که به جا و درست ازشون استفاده بشه.
🔖 هشتگها:
#CSharp #DotNet #OOP #Encapsulation