جلوگیری از NullReferenceException در #C مدرن: راهکارهای نوین برای کدنویسی امنتر
نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۳/۰۱ ۰۸:۰۷
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
user دارید که میتواند دارای یک Address (آدرس) باشد و Address نیز میتواند دارای یک City (شهر) باشد. در گذشته، برای دسترسی ایمن به نام شهر، باید بررسیهای متعددی را انجام میدادید:if (user != null && user.Address != null && user.Address.City != null)
{
Console.WriteLine(user.Address.City);
}NullReferenceException در زمان اجرا شود، که یافتن و رفع آن میتواند زمانبر باشد.?.) و ادغام تهی (??)، رویکرد ما را نسبت به مدیریت مقادیر تهی متحول کرده است. این عملگرها به شما امکان میدهند که کدهای دفاعی را به یک خط کد زیبا و خوانا تبدیل کنید.?.?. به شما اجازه میدهد تا به صورت ایمن به اعضای یک شیء دسترسی پیدا کنید یا متدهای آن را فراخوانی کنید. اگر هر بخشی از زنجیره دسترسی تهی باشد، کل عبارت به null ارزیابی میشود و از بروز NullReferenceException جلوگیری میکند. به عبارت دیگر، این عملگر "میانبر" میزند (short-circuits) اگر هر جزء از مسیر دسترسی، تهی باشد.Console.WriteLine(user?.Address?.City);
user تهی باشد، یا اگر user تهی نباشد اما Address آن تهی باشد، کل عبارت به null ارزیابی میشود. در این حالت، Console.WriteLine یک مقدار تهی را چاپ خواهد کرد. این رویکرد به طور قابل توجهی کد را تمیزتر و خلاصهتر میکند.logger دارید و میخواهید یک متد Log را روی آن فراخوانی کنید، اما فقط در صورتی که logger تهی نباشد:logger?.Log("Processing");logger?.Log("Processing")، متد Log تنها در صورتی فراخوانی میشود که logger یک شیء معتبر باشد. اگر logger تهی باشد، هیچ اتفاقی نمیافتد و برنامه به صورت عادی به کار خود ادامه میدهد، بدون اینکه خطای NullReferenceException رخ دهد.???? مکمل ?. است و به شما اجازه میدهد تا یک مقدار پیشفرض را در صورتی که عبارت سمت چپ آن تهی باشد، تعیین کنید. این عملگر برای فراهم کردن یک مقدار جایگزین در سناریوهایی که ممکن است نتیجه ?. تهی باشد، بسیار مفید است.Console.WriteLine(user?.Address?.City ?? "Unknown City");
user یا Address یا City هر یک تهی باشند، کل عبارت user?.Address?.City به null ارزیابی میشود. سپس، عملگر ?? وارد عمل شده و مقدار "Unknown City" را به عنوان خروجی نهایی انتخاب میکند. این ترکیب از عملگرها، راهی قدرتمند برای تعریف ایمنترین سناریوهای بازگشت (fallback scenarios) در یک خط کد است.?. و ?? در سناریوهای مختلفی در توسعه برنامههای .NET کاربرد دارد:_logger?.LogInformation("User signed in at {Time}", DateTime.UtcNow);_logger تهی باشد (مثلاً در یک محیط تست که لاگگیری فعال نیست)، متد LogInformation فراخوانی نمیشود و از بروز خطا جلوگیری میشود.var phone = customer?.ContactInfo?.Phones?.FirstOrDefault()?.Number ?? "N/A";
customer با ساختار تودرتو استخراج میکند. اگر هر یک از عناصر میانی (مانند ContactInfo یا Phones) تهی باشند، یا اگر لیستی از تلفنها خالی باشد، مقدار "N/A" بازگردانده میشود.var firstActive = users?.FirstOrDefault(u => u.IsActive)?.Name ?? "Unknown";
users استخراج میکند و نام آن را برمیگرداند. اگر users تهی باشد یا هیچ کاربر فعالی یافت نشود، مقدار "Unknown" برگردانده میشود.if را با الگوهای شیء (object patterns) ترکیب کنید تا بررسیهای تهی را به صورت ضمنی و زیبا انجام دهید:if (user is { Address.City: "New York" })
{
Console.WriteLine("User lives in NYC");
}user is { Address.City: "New York" } به صورت خودکار بررسی میکند که آیا user تهی است، و سپس بررسی میکند که آیا Address تهی است و آیا City برابر با "New York" است. اگر هر یک از این شرایط برقرار نباشد (مثلاً user یا Address تهی باشد)، شرط if به false ارزیابی میشود و از بروز NullReferenceException جلوگیری میشود.?. بر روی انواع مقداری که قابل تهی نیستند (مانند int یا DateTime) خودداری کنید. اگر میخواهید این عملگرها را با انواع مقداری استفاده کنید، باید از نسخههای قابل تهی آنها (nullable types) مانند int? یا DateTime? استفاده کنید.?. برای دسترسی ایمن عالی است، اما نباید برای مدیریت جریان کنترل برنامه به صورت گسترده از آن استفاده کرد. برای تصمیمگیریهای پیچیدهتر، ساختارهای if-else سنتی ممکن است خوانایی بیشتری داشته باشند.NullReferenceException نشاندهنده یک مشکل منطقی در برنامه است که باید برطرف شود، نه اینکه صرفاً از آن اجتناب شود.?.) و ادغام تهی (??)، یک گام بزرگ در جهت افزایش امنیت، خوانایی و کارایی کد برداشته است. این ابزارها، که در نگاه اول ممکن است صرفاً "شکر نحوی" (syntactic sugar) به نظر برسند، در واقع سپری قدرتمند در برابر یکی از رایجترین و مزاحمترین خطاهای .NET هستند. با پذیرش و استفاده صحیح از این قابلیتها، توسعهدهندگان میتوانند از نوشتن کدهای دفاعی طولانی و تکراری اجتناب کرده و بر روی منطق اصلی برنامه تمرکز کنند. کد نویسی ایمن در برابر تهی (null-safe) نه تنها به معنای کدهای تمیزتر است، بلکه به کاهش باگها و افزایش بهرهوری در فرآیند توسعه نرمافزار نیز کمک شایانی میکند. با استفاده از این تکنیکها، میتوانید کدی بنویسید که نه تنها عملکردی صحیح دارد، بلکه خوانایی و نگهداری آن نیز آسانتر است و شما را قادر میسازد تا روی ساخت قابلیتهای جدید و نوآورانه تمرکز کنید.