عنوان:

‫نگاهی جامع به ویژگی‌های جدید C# 14 و برنامه‌های آینده برای C# 15


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۵/۲۵ ۱۱:۴۷
آدرس: www.dntips.ir
در یک ارائه فنی، مت تورگِرسِن (Matt Torgersen)، طراح ارشد زبان برنامه‌نویسی #C، به تشریح ویژگی‌های جدید و بهبودهای کلیدی نسخه ۱۴ این زبان پرداخت که برای انتشار در ماه نوامبر برنامه‌ریزی شده است. وی همچنین چشم‌اندازی از یکی از مهم‌ترین ویژگی‌های در دست طراحی برای C# 15 را به اشتراک گذاشت. تمام ویژگی‌های معرفی‌شده برای C# 14 در حال حاضر از طریق کانال پیش‌نمایش ویژوال استودیو (Visual Studio Preview Channel) در دسترس توسعه‌دهندگان قرار دارند.

بهبودهای جزئی اما کاربردی

نسخه جدید C# شامل مجموعه‌ای از بهبودهای کوچک است که با هدف رفع برخی محدودیت‌ها و افزایش راحتی توسعه‌دهندگان طراحی شده‌اند.
یکی از این بهبودها، گسترش عملکرد عملگر شرطی تهی (Null-Conditional Operator) با نماد ?. است. پیش از این، استفاده از این عملگر در سمت چپ یک عبارت انتساب (Assignment) ممکن نبود. در C# 14، این محدودیت برداشته شده و اکنون می‌توان از آن برای انتساب‌های شرطی استفاده کرد. با این ویژگی، اگر مقدار سمت چپ عملگر null باشد، کل عملیات انتساب، شامل ارزیابی عبارت سمت راست، نادیده گرفته می‌شود. این قابلیت نیاز به نوشتن بلوک‌های if برای بررسی null بودن اشیاء را کاهش می‌دهد.
بهبود دیگر در زمینه عبارات لامبدا (Lambda Expressions) صورت گرفته است. تا پیش از این، اگر پارامترهای یک عبارت لامبدا نیاز به اصلاح‌کننده‌هایی (Modifiers) مانند out یا ref داشتند، توسعه‌دهنده مجبور بود از فرم طولانی تعریف لامبدا استفاده کرده و نوع همه پارامترها را به صراحت مشخص کند. در C# 14، اکنون می‌توان از این اصلاح‌کننده‌ها در فرم کوتاه و مختصر لامبداها نیز استفاده کرد که باعث خوانایی و سادگی بیشتر کد می‌شود.
علاوه بر این، عملکرد دستور nameof برای انواع عمومی (Generic Types) نیز بهبود یافته است. در نسخه‌های قبلی، برای استفاده از nameof روی یک نوع عمومی، حتماً باید یک آرگومان نوع (Type Argument) مشخص می‌شد، حتی اگر این آرگومان در خروجی نهایی نادیده گرفته می‌شد. اکنون می‌توان از nameof بدون مشخص کردن آرگومان نوع استفاده کرد (مثلاً nameof(List<>)) که این ویژگی را با typeof هماهنگ می‌کند.

گسترش اعضای جزئی (Partial Members)

کلاس‌های جزئی (Partial Classes) ابزاری قدرتمند برای جداسازی بخش‌های مختلف یک کلاس هستند، به‌ویژه در سناریوهایی که بخشی از کد توسط انسان و بخش دیگر توسط ابزارهای تولید خودکار کد (Source Generators) ایجاد می‌شود. متدهای جزئی (Partial Methods) از دیرباز وجود داشته‌اند تا ارتباطی کنترل‌شده بین این دو بخش برقرار کنند. در C# 13، این قابلیت به خصوصیات (Properties) و ایندکسرها (Indexers) گسترش یافت. C# 14 این مسیر را با افزودن پشتیبانی از رویدادهای جزئی (Partial Events) و سازنده‌های جزئی (Partial Constructors) تکمیل می‌کند. این ویژگی به توسعه‌دهنده اجازه می‌دهد تا تعریف یک عضو را در یک فایل مشخص کرده و پیاده‌سازی آن را به بخش دیگر کد، که اغلب توسط یک Source Generator تولید می‌شود، واگذار کند.

دسترسی به فیلد در خصوصیات خودکار: معرفی کلیدواژهfield

یکی از مهم‌ترین تغییرات C# 14، معرفی قابلیت دسترسی به فیلد پشتیبان (Backing Field) در خصوصیات خودکار (Auto-Properties) است. پیش از این، اگر توسعه‌دهنده‌ای نیاز داشت حتی یک منطق کوچک به بخش get یا set یک خصوصیت اضافه کند، مجبور بود از خصوصیت خودکار صرف‌نظر کرده، یک فیلد پشتیبان به صورت دستی تعریف کند و هر دو بخش get و set را به طور کامل پیاده‌سازی نماید.
C# 14 با معرفی کلیدواژه متنی field این مشکل را حل می‌کند. این کلیدواژه به توسعه‌دهنده اجازه می‌دهد تا درون بخش‌های get یا set یک خصوصیت خودکار، به فیلد پشتیبان که توسط کامپایلر به صورت خودکار تولید شده است، دسترسی مستقیم داشته باشد. این ویژگی نه تنها کد را کوتاه‌تر و خواناتر می‌کند، بلکه با مخفی نگه داشتن فیلد پشتیبان از سایر اعضای کلاس، به کپسوله‌سازی (Encapsulation) بهتر نیز کمک می‌کند.
معرفی field به عنوان یک کلیدواژه جدید، یک تغییر شکننده (Breaking Change) محسوب می‌شود؛ زیرا ممکن است کدهای موجود از متغیری با همین نام در بدنه خصوصیات استفاده کرده باشند. برای مدیریت این موضوع، کامپایلر یک هشدار صادر می‌کند و توسعه‌دهندگان می‌توانند با استفاده از this.field یا @field به متغیر قدیمی خود اشاره کرده و کد را تصحیح کنند.

اعضای افزونه (Extension Members): بزرگترین ویژگی C# 14

بزرگترین و مهم‌ترین ویژگی C# 14، معرفی اعضای افزونه (Extension Members) است. متدهای افزونه (Extension Methods) که از C# 3 معرفی شدند، به دلیل افزایش قابلیت کشف (Discoverability) و خوانایی کد، بسیار موفق بودند. با این حال، نحو (Syntax) تعریف آن‌ها، که مبتنی بر متدهای استاتیک در کلاس‌های استاتیک بود، قابلیت تعمیم به سایر اعضا مانند خصوصیات یا عملگرها را نداشت.
C# 14 با معرفی یک نحو جدید به نام بلوک افزونه (extension block) این محدودیت را برطرف می‌کند. در این ساختار جدید، به جای تعریف متدهای استاتیک، یک بلوک extension برای یک نوع مشخص تعریف می‌شود و تمام اعضای افزونه درون آن به گونه‌ای نوشته می‌شوند که گویی اعضای نمونه (Instance Members) آن نوع هستند.
این نحو جدید نه تنها امکان تعریف خصوصیات افزونه (Extension Properties) و عملگرهای افزونه (Extension Operators) را فراهم می‌کند، بلکه می‌تواند برای تعریف اعضای استاتیک افزونه (Extension Static Members) نیز به کار رود. این قابلیت برای افزودن متدهای کارخانه‌ای (Factory Methods) به انواع موجود و افزایش قابلیت کشف آن‌ها بسیار مفید است.
نکته بسیار مهم در مورد این ویژگی، سازگاری کامل با کدهای قدیمی است. کامپایلر C# 14، اعضای افزونه تعریف‌شده با نحو جدید را در پس‌زمینه به همان فرمت قدیمی (متدهای استاتیک) کامپایل می‌کند. این بدان معناست که کدهای نوشته‌شده با کامپایلرهای قدیمی‌تر یا سایر زبان‌های دات‌نت، بدون هیچ مشکلی می‌توانند از این اعضا استفاده کنند و هیچ‌گونه شکست در سازگاری (Breaking Change) رخ نخواهد داد.


نگاهی به آینده: انواع Union در C# 15

تورگِرسِن در پایان ارائه، به معرفی طرح‌های اولیه برای یک ویژگی بزرگ در C# 15 با نام انواع Union پرداخت. این ویژگی با الهام از قابلیت‌های موجود در زبان‌هایی مانند TypeScript و F# طراحی شده است اما رویکردی منحصر به فرد را دنبال می‌کند. در C#، این ویژگی به صورت Nominal Type Unions پیاده‌سازی خواهد شد. این بدان معناست که:
۱. Nominal (اسمی): یک نوع Union باید به صراحت با یک نام مشخص تعریف شود (مانند union Pet of Dog | Cat | Bird;).
۲. Type Union (اجتماع نوعی): اعضای تشکیل‌دهنده Union، انواع (Types) موجود در C# هستند و نه برچسب‌های جداگانه. این انواع می‌توانند از پیش تعریف شده باشند و نیازی به ارتباط مستقیم با تعریف Union ندارند.

یک تبدیل ضمنی (Implicit Conversion) از انواع تشکیل‌دهنده به نوع Union وجود خواهد داشت. مصرف این نوع عمدتاً از طریق تطبیق الگو (Pattern Matching) صورت می‌گیرد و کامپایلر بررسی می‌کند که آیا تمام حالات ممکن در یک عبارت switch پوشش داده شده‌اند یا خیر (Exhaustiveness Checking). پیاده‌سازی این ویژگی در سطح پایین، به صورت یک struct ساده خواهد بود که یک فیلد از نوع object را در خود جای می‌دهد. تیم طراحی C# در حال کار بر روی این ویژگی است و امیدوار است که نمونه‌های اولیه آن به زودی برای بازخورد در اختیار جامعه توسعه‌دهندگان قرار گیرد.


مشاهده مطلب اصلی