C# 9.0: init-only - ایجاد خصوصیات تغییر ناپذیر بدون سازنده

در نوشته قبلی، شما با جملات سطح-بالا C# 9.0 آشنا شدید. در این نوشته شما با ویژگی دیگری از C# 9.0 آشنا می‌شوید که ویژگی init-only نامیده می‌شود.

در نوامبر 2007 مایکروسافت C# 3.0 را با انتشار NET Framework 3.5. معرفی کرد. C# 3.0 بسیاری از مفاهیم جدید، به عنوان مثال زبان پرس و جو یکپارچه (LINQ) را ارائه داده است. همچنین مفهوم قدرتمند مقداردهی اولیه اشیاء را معرفی کرد. این‌ها پایه و اساسی برای ویژگی init-only هستند که با C# 9.0 معرفی شده است، بنابراین بیایید با مقداردهی اولیه اشیاء شروع کنیم.

درک مقداردهی اولیه اشیاء

فرض کنید شما یک کلاس Friend با دو خصوصیت FirstName و LastName دارید:

به طور سنتی، می توانید با فراخوانی سازنده پیش فرض و پس از آن مقداردهی اولیه خصوصیات، یک شئ از Friend را مانند زیر ایجاد کنید:

به جای سه عبارت فوق، می‌توانید از یک دستور با مقداردهنده اولیه شئ، همانند تکه کد زیر استفاده کنید. مقداردهی اولیه شئ همچنین سازنده پیش فرض را فراخوانی می‌کند و سپس با فراخوانی setter دو خصوصیت FirstName و LastName را مقداردهی اولیه می‌کند:

ایجاد خصوصیات غیرقابل تغییر

مشکلی که در مقداردهی اولیه اشیا وجود دارد این است که به شما امکان ایجاد خصوصیات تغییرناپذیر را حداقل تا قبل از C# 9.0 نمی‌دهد. خصوصیات غیرقابل تغییر خصوصیاتی هستند که پس از ایجاد شئ، نمی‌توانید آن را تغییر دهید. اما در این مورد، شما می‌توانید به عنوان مثال خصوصیت FirstName یک Friend را در هر زمان پس از ایجاد شئ Friend تغییر دهید. تکه کد زیر این را نشان می‌دهد:

برای ایجاد خصوصیات تغییر ناپذیر، باید یک سازنده مانند تکه کد زیر ایجاد کنید که firstname و lastname را به عنوان پارامتر در نظر بگیرد. توجه داشته باشید که من setter‌های خصوصیت‌ها را حذف کرده‌ام، این بدان معنی است که پس از مقدار دهی اولیه شئ Friend نمی‌توان خصوصیت‌ها را تغییر داد. تعریف فقط یک getter با Auto property به اصطلاح get-only Auto Property نامیده می‌شود. این یک ویژگی است که با 6.0 #C و NET Framework 4.6. در سال 2015 معرفی شده است. Get-only Auto Properties می‌توانند مستقیماً یا مانند تکه کد زیر در سازنده مقداردهی اولیه شوند. این منطق همان فیلدهای فقط‌خواندنی (readonly) است؛ همچنین می‌توان آن‌ها را مستقیماً یا در یک سازنده مقداردهی اولیه کرد.

با کلاس Friend که در بالا تعریف شده است، پس از ایجاد شئ Friend نمی‌توانید خصوصیت FirstName یا LastName را تغییر دهید. در زیر این را امتحان می کنم، می‌بینید که خطایی مشاهده می‌شود که می‌گوید خصوصیت FirstName فقط خواندنی است.

اکنون مشکل خود را حل کردیم، خصوصیت‌های FirstName و LastName غیرقابل تغییر هستند. اما برای رسیدن به این هدف، ما باید یک سازنده تعریف می‌کردیم.

با C# 9.0 می‌توانید خصوصیات تغییر ناپذیری بدون سازنده ایجاد کنید: این مورد با ویژگی init-only ممکن می‌شود.

مفهوم ویژگی init-only در C# 9.0

در تکه کد زیر یک کلاس Friend را می‌بینید که کاملاً مشابه کلاس Friend تعریف شده در تکه کد قبلی است. و دقیقاً همان کار را می‌کند. اما آیا می‌توانید تفاوتی را مشاهده کنید؟

تفاوت در کلمه کلیدی init است که برای Auto Properties استفاده می‌شود. کلمه کلیدی init برای تعریف نوع خاصی از set accessor استفاده می‌شود (این بدان معنی است که اگر از init و set در یک Auto Properties تک استفاده کنید خطا می‌دهد). این خصوصیات اکنون اصطلاحاً به ویژگی init-only گفته می‌شوند. این بدان معناست که شما فقط می‌توانید این خصوصیات را در سازنده مانند تکه کد بالا، یا مستقیماً مانند تکه کد زیر...

... یا *drumrolls*… در مقداردهی اولیه شئ ذکر کنید. این باعث می‌شود سازنده‌ای که در بالا استفاده کردیم برای تعریف خصوصیات تغییرناپذیر غیر ضروری باشد. بیایید به این نگاه کنیم.

ویژگی init-only و مقداردهی اولیه شئ

در تکه کد زیر یک کلاس Friend با ویژگی init-only و بدون سازنده مشاهده می‌کنید. در واقع، این کلاس Friend دقیقاً همان کلاس Friend نشان داده شده در ابتدای این نوشته است. تنها تفاوت در این است که ما از کلمه کلیدی init به جای کلمه کلیدی set برای Auto Properties استفاده کردیم، که ویژگی init-only آن‌ها را می‌سازد.

همانطور که قبلاً ذکر شد این بدان معناست که، می‌توانید خصوصیات را فقط در یک سازنده، مستقیماً یا در مقداردهی اولیه شئ، مقداردهی کنید. کلاس Friend ما سازنده ندارد، بنابراین اجازه دهید از مقداردهنده اولیه شئ استفاده کنیم:

به خوبی کار می‌کند. اما اکنون نکته مهم این است که پس از ایجاد شئ نمی‌توان خاصیت را تغییر داد. و این قدرت ویژگی init-only است. در تصویر زیر سعی می‌کنم خصوصیت FirstName را بعد از مقداردهی اولیه شئ Friend تنظیم کنم. همانطور که مشاهده می‌کنید، با خطایی روبرو می‌شوم که می‌گوید ویژگی init-only خاصیت FirstName را فقط می‌توان در مقداردهنده اولیه شئ، سازنده یا init accessor اختصاص داد.

مقادیری که برای ویژگی init-only لازم نیست

لازم به ذکر است که مقادیر برای ویژگی init-only لازم نیستند، آن‌ها اختیاری هستند. همچنین می‌توانید همانطور که با Auto Properties عادی انجام می‌دهید، فقط خصوصیت‌های مورد نظر خود را تنظیم کنید. به عنوان مثال فقط می‌توانید خصوصیت FirstName یک شئ Friend را در تکه کد زیر تنظیم کنید، که کاملاً معتبر است. اما از آنجایی که ما از ویژگی init-only استفاده می‌کنیم، بعد از این دستور شما دیگر فرصتی برای تنظیم خصوصیت LastName ندارید، زیرا خصوصیت‌ها غیرقابل‌تغییر هستند:

تنظیم فیلد‌های فقط‌خواندنی (Readonly)

همانطور که در حین مقداردهی اولیه شئ، init accessor از ویژگی init-only فراخوانی می‌شود، امکان تنظیم فیلد فقط‌خواندنی (readonly) در init accessor مجاز است، دقیقاً به همان روشی که می‌توانید آن‌ها را در سازنده تنظیم کنید. اگر می‌خواهید مقدار خصوصیت اختصاص داده شده را بررسی کنید، این کار می‌تواند مفید واقع شود. به عنوان مثال اختصاص دادن فضای خالی (whitespace) یا null برای خصوصیت‌های FirstName و LastName معنی چندانی ندارد. بنابراین، می‌توانید کلاس Friend را مانند زیر ایجاد کنید و فیلد‌های فقط‌خواندنی (readonly) را در init accessor‌های خصوصیت‌ها قرار دهید. خصوصیات هنوز تغییرناپذیر هستند، اما اگر در مقداردهی اولیه شئ فضای خالی (whitespace) یا null اختصاص دهید - این تنها راه تنظیم خصوصیات آن کلاس است زیرا هیچ سازنده‌ای تعریف نشده است - یک ArgumentExceptionدریافت می‌کنید.

خلاصه

ویژگی init-only، یک ویژگی قدرتمند است. آن‌ها به شما امکان می‌دهند خصوصیات تغییرناپذیر را بدون تعریف سازنده‌ای که مقادیر خصوصیت اولیه را می‌گیرد، ایجاد کنید. در حالی که تنظیم ویژگی init-only از سازنده کار می‌کند، شما همچنین می‌توانید ویژگی init-only را با مقداردهنده اولیه شئ تنظیم کنید، و بعداً نمی‌توانید آن‌ها را تغییر دهید، زیرا غیرقابل‌تغییر هستند. اگر قصد دارید با داده‌های تغییرناپذیر در #C کار کنید، این یک ویژگی بسیار مفید است.

علاوه بر ویژگی init-only، در C# 9.0 تعداد بیشتری ویژگی برای کار با داده‌های تغییرناپذیر وجود دارد: در نوشته بعدی، شما در مورد انواع Record یاد خواهید گرفت.


Source: Thomas Claudius Huber - C# 9.0: Init-only Properties – Create Immutable Properties Without Constructor Boilerplate


مقالات بیشتر در دات نت زوم

https://t.me/DotNetZoom