حفاظت از دادهها و افزایش استحکام کد با Array.AsReadOnly در #C
نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۳/۱۱ ۰۹:۱۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
Array.AsReadOnly. این مقاله به بررسی عمیق این ابزار، دلایل سودمندی آن، موارد استفاده پیشرفته و مقایسه آن با گزینههای دیگر مانند ImmutableArray میپردازد.Array.AsReadOnly یک متد استاتیک (static method) است که یک آرایه موجود را در یک ReadOnlyCollection محصور (wrap) میکند و دسترسی فقط-خواندنی (read-only) به عناصر آرایه را فراهم میآورد. نکته بسیار مهم این است که Array.AsReadOnly یک کپی جدید از آرایه ایجاد نمیکند. در عوض، یک پوشش سریع و بدون هزینه اضافی (zero-cost wrapping) دور آرایه اصلی ایجاد میکند. این بدان معناست که عملکرد برنامه تحت تأثیر منفی قرار نمیگیرد.int[] numbers = { 1, 2, 3 };
var readOnlyNumbers = Array.AsReadOnly(numbers);
readOnlyNumbers[0] = 10; // خطا: مجموعه فقط-خواندنی است
numbers[0] = 10; // این کار مجاز است و محتوای readOnlyNumbers نیز تغییر میکندreadOnlyNumbers یک نماینده فقط-خواندنی از آرایه numbers است. تلاش برای تغییر یک عنصر از طریق readOnlyNumbers منجر به خطا در زمان کامپایل یا اجرا میشود. اما آرایه اصلی numbers همچنان قابل تغییر است و این تغییرات در readOnlyNumbers نیز منعکس خواهد شد، زیرا هر دو به یک مکان حافظه اشاره دارند.Array.AsReadOnly در سناریوهای خاصی بسیار ارزشمند است. اصلیترین دلیل، محافظت از آرایههای داخلی بدون نیاز به شبیهسازی (cloning) پرهزینه است. این ویژگی به شما امکان میدهد آرایهها را به طور ایمن بین کلاسها یا لایههای مختلف به اشتراک بگذارید. همچنین، به ایجاد رابطهای برنامهنویسی کاربردی (API) تمیز و تغییرناپذیر (immutable) بدون از دست دادن عملکرد کمک میکند. به طور خلاصه، Array.AsReadOnly اشتراکگذاری ایمن با حداقل سربار عملکردی را فراهم میکند. این یک دفاع سریع در برابر تغییرات ناخواسته یا مخرب است.Array.AsReadOnly فراتر از یک ابزار ساده، کاربردهای عملی و پیشرفتهای در بهبود استحکام و امنیت کد دارد.public class Library
{
private int[] _data = { 1, 2, 3 }; // دادههای داخلی
public int[] GetData() => _data; //دسترسی مستقیم به آرایه
}GetData را فراخوانی میکند، میتواند محتوای آرایه _data را تغییر دهد.public class Library
{
private readonly int[] _data = { 1, 2, 3 }; // دادههای داخلی و فقط-خواندنی
public ReadOnlyCollection<int> GetData() => Array.AsReadOnly(_data);
}Array.AsReadOnly میتواند در این زمینه مفید باشد.public class Invoice
{
private readonly LineItem[] _lineItems; // آرایه داخلی برای آیتمهای فاکتور
public Invoice(LineItem[] items)
{
_lineItems = items ?? throw new ArgumentNullException(nameof(items));
}
public ReadOnlyCollection<LineItem> LineItems => Array.AsReadOnly(_lineItems);
}Invoice، پس از ایجاد نمونه، لیست LineItems از طریق یک مجموعه فقط-خواندنی در دسترس قرار میگیرد. این تضمین میکند که پس از ایجاد شیء، هیچ تغییر خارجی در لیست آیتمهای فاکتور امکانپذیر نیست و وضعیت داخلی آن پایدار میماند.Array.AsReadOnly به محافظت از این دادهها کمک میکند.public static class Config
{
private static readonly string[] _supportedFormats = { "json", "xml", "yaml" };
public static ReadOnlyCollection<string> SupportedFormats => Array.AsReadOnly(_supportedFormats);
}public class SharedResource
{
private readonly int[] _sharedData = { 1, 2, 3 }; // دادههای اشتراکی
// متدی برای دریافت دادههای اشتراکی به صورت فقط-خواندنی
public ReadOnlyCollection<int> GetSharedData() => Array.AsReadOnly(_sharedData);
}public class MenuViewModel
{
private readonly string[] _menuItems = { "Home", "About", "Contact" };
public ReadOnlyCollection<string> MenuItems => Array.AsReadOnly(_menuItems);
}Array.AsReadOnlyوImmutableArray<T>Array.AsReadOnly یک لایه حفاظتی ایجاد میکند، اما "تغییرناپذیری واقعی" را تضمین نمیکند، زیرا آرایه اصلی همچنان میتواند تغییر کند (اگر ارجاعی به آن وجود داشته باشد). در مقابل، ImmutableArray مجموعهای واقعاً تغییرناپذیر است. هرگونه "تغییر" در ImmutableArray منجر به ایجاد یک نمونه جدید از مجموعه با تغییرات اعمال شده میشود و نمونه اصلی دستنخورده باقی میماند.| ویژگی | Array.AsReadOnly | <ImmutableArray<T |
| عملکرد | سریع (کپی صفر) | کمی کندتر (کپی کردن دادهها) |
| حافظه | کم | بالاتر (به دلیل ایجاد کپی جدید) |
| تغییرناپذیری واقعی | خیر | بله |
| ایمنی در برابر تغییر | فقط از طریق پوشش (Wrapper) | ایمنی کامل |
| بهترین مورد استفاده | اشتراکگذاری دادههای داخلی کنترلشده | APIهای عمومی که نیاز به تضمین تغییرناپذیری دارند |
Array.AsReadOnly زمانی استفاده کنید که عملکرد اهمیت دارد و دادهها به صورت داخلی کنترل میشوند.ImmutableArray<T> زمانی استفاده کنید که به تضمینهای واقعی تغییرناپذیری برای APIهای عمومی نیاز دارید.ReadOnlyCollection<T> را به جای آرایههای خام در APIهای عمومی خود ارائه دهید.IReadOnlyList<T> ترکیب کنید تا حداکثر انعطافپذیری را داشته باشید.Array.AsReadOnly و ImmutableArray را از نظر ایجاد کپی از دادهها توصیف میکند؟Array.AsReadOnly یک کپی جدید ایجاد میکند، اما ImmutableArray<T> این کار را نمیکند.Array.AsReadOnly یک کپی جدید ایجاد نمیکند (wrapper است)، اما ImmutableArray<T> یک کپی جدید از دادهها ایجاد میکند.Array.AsReadOnly، با وجود سادگی ظاهری، ابزاری بسیار کارآمد در جعبهابزار توسعهدهندگان .NET است. این متد با فراهم آوردن امکان اشتراکگذاری ایمن آرایهها بدون سربار عملکردی قابل توجه، به ساخت برنامههایی امنتر، مقیاسپذیرتر و مستحکمتر کمک شایانی میکند. درک صحیح زمان و نحوه استفاده از Array.AsReadOnly میتواند از بروز بسیاری از کلاسهای باگ، از جمله مشکلات چندنخی و سوءاستفاده تصادفی از API، جلوگیری کند. با بهکارگیری هوشمندانه این ابزار، میتوان کیفیت و پایداری کد را به میزان قابل توجهی افزایش داد.Array.AsReadOnly یک کپی جدید ایجاد نمیکند (wrapper است)، اما ImmutableArray یک کپی جدید از دادهها ایجاد میکند.