وبلاگ شخصی حامد شیربندی

حامد شیربندی

توسعه دهنده نرم افزار

بررسی کلمه کلیدی Static در #C

از کلمه کلیدی static به عنوان یک modifier در #C ، برای تعریف یک عضو ایستا ( static ) استفاده میشود. این اعضا به صورت مستقیم از طریق نام کلاسی که در آن معرفی شده اند در دسترس خواهند بود یعنی برای دسترسی به آنها نیازی به نمونه سازی از کلاس مربوطه نیست و نیز باید در نظر داشت که این اعضا به صورت سراسری در سطح برنامه تعریف شده و فقط یک نمونه از آنها در یک فضای اشتراکی قرار گرفته و در کل برنامه در دسترس خواهد بود.

کلمه ی کلیدی static به همراه کلاس ها، فیلدها، پراپرتی ها، سازنده ها، رویدادها (events) و اپراتورها (operators) استفاده میشود.

پیشنهاد میشود قبل از خواندن ادامه این نوشته، ابتدا نگاهی به مقاله زیر بیاندازید و با فضاهایHeap، Stack و Static آشنا شوید :

آبجکت هایی که می سازیم چه میشوند؟ آشنایی با فضای Heap ، Stack و Static
 

پراپرتی ها و فیلدهای static

اگر یک پراپرتی در سطح یک کلاس به صورت استاتیک تعریف شود چیزی که برای آن اتفاق می افتد این است که مقدار آن در حافظه ی static رم قرار میگرید و دسترسی به آن در سراسر برنامه امکان پذیر میشود. طول عمر انواع static در سطح Domain (Domain Level) می باشد و تا زمانی که برنامه روی IIS به کارش ادامه دهد این پراپرتی هم در دسترس خواهد بود.

در برنامه های وب باید در نظر داشت که مقدار موجود در پراپرتی از نوع static بین تما Request ها به اشتراک گذاشته میشود پس در این مورد باید خیلی مراقب این نوع خاص و طرز استفاده ی از آن بود.

نکته ی ظریفی که در مورد انواع static وجود دارد این است که آنها حتی قبل از اولین دسترسی در برنامه توسط سایر قسمت ها، لاود شده و در حافظه قرار میگیرند چون CLR (Common Language Runtime) با لاود کردن کلاس یا namespace ی که حاوی اعضا یا کلاس های استاتیک باشد، آنها را نیز در همان لحظه در حافظه لاود میکند و منتظر دسترسی سایر قسمت ها به این اعضا نمیشود.

پس از تعریف یک پراپرتی به صورت static داخل یک کلاس باید دانست که نیازی به نمونه سازی از آن کلاس برای دسترسی به آن پراپرتی نداریم و به صورت مستقیم از طریق نام کلاس میتوانیم به تمام اعضای static آن از جمله پراپرتی ها و متدها دسترسی داشته باشیم.

درست برخلاف مورد فوق، اگر یک نمونه از کلاس مذکور ایجاد کنیم خواهیم دید که به هیچ یک از اعضای static آن دسترسی نخواهیم داشت. دلیل آن چیست؟

اعضای استاتیک در C# قابل نمونه سازی نیستند به همین دلیل در یک نمونه ی ایجاد شده از کلاس در دسترس نخواهند بود.
 کلاس زیر را در نظر بگیرید :

public class User
 {
 public static int UserId {get; set;};
 public string UserName {get; set;};
 }

در کلاس User دو پراپرتی داریم که یکی از آنها static است. این عضو هیچ نیازی به نمونه سازی کلاس User ندارد و به صورت زیر در دسترس است :

 var userId= User.UserId;

عضو دیگر این کلاس یعنی UserName اصطلاحا none-static یا غیر استاتیک است. این عضو قابل نمونه سازی بوده و به صورت مستقیم در دسترس نخواهد بود و نیز با هر نمونه ای که از کلاس ساخته میشود، یک نمونه ی کاملا مجزا از این عضو هم ایجاد شده و در حافظه stack قرار میگیرد.

کلاس های static 

وقتی یک کلاس را از نوع استاتیک تعریف میکنیم دیگر نمیتوانیم عضو غیر استاتیکی در آن داشته باشیم و نیز هیچگاه نمیتواینم از آن ارث بری کنیم زیرا کلاس static به صورت پیشفرض مثل یک کلاس sealed در نظر گرفته میشود چون این کلاسها هیچ نوع رفتاری را تعریف نمیکنند و نمیتوانند یک اینترفیس را پیاده کنند. کلاس های static بجز از کلاس object نمیتوانند از هیچ کلاس دیگری ارث بری کنند.
 هر کلاسی که خودش static باشد و یا اینکه عضو staticی داشته باشد. دات نت به صورت پیشفرض برای آن کلاس یک سازنده static در نظر میگیرد حتی اگر این سازنده در بدنه کلاس پیاده نشده باشد.

این سازنده استاتیک تنها یکبار و آن هم در اولین دسترسی به کلاس اجرا می شود و از آن میتوان برای مقدار دهی اعضای استاتیک کلاس استفاده کرد.
 معمولا زمانی یک کلاس را به صورت استاتیک تعریف میکنیم که وابستگی به سایر کلاس های برنامه نداشته و حاوی امکاناتی است که به صورت سراسری در برنامه قابل استفاده هستند. برای مثال یک کلاس ایجاد کرده ایم که شامل چندین متد و پراپرتی برای کار با تاریخ شمسی است. این کلاس و هر کلاس دیگری که مثل این میتواند نقش Utility ایفا کند را میتوانیم از نوع استاتیک در نظر بگیریم.

public static class PersianDateTimeHelper
 {
 public static int GetYear(DateTime dt)
 {
 //...
 }

 public static string GetMonth(DateTime dt)
 {
 //...
 }

 public static int GetShortDate(DateTime dt)
 {
 //...
 }
 }

اما این چه مزیتی برای ما خواهد داشت ؟
 با استاتیک تعریف کردن یک کلاس، در زمان اجرا با اولین برخورد CLR به آن کلاس یک نمونه از آن ایجاد شده و در فضای static از رم قرار داده میشود و برای سایر دسترسی ها در سطح برنامه و برای همه ی کاربران، از همان وهله ی آماده استفاده شده و یک وهله سازی اضافه در طول برنامه کاسته میشود.

 متدهای static 

یک کلاس غیر استاتیک میتواند در کنار اعضای غیر استاتیکش متدهای استاتیک هم داشته باشد، بدیهی است که این متدها نیازی به وهله سازی کلاس ندارند و به صورت مستقیم با نام کلاس در دسترس هستند.
 کامپایلر هم این متدها را در اولین دسترسی به کلاس، به فضای Static برده و بعد از آن برای تمام فراخوانی های آن متدها از همان نمونه های داخل فضای static استفاده میکند (این مورد برای همه ی اعضای استاتیک شامل فیلد ها، پراپرتی ها و متدها صدق میکند).
 اما تعریف متدهای استاتیک داخل کلاس غیر استاتیک چند نکته هم دارد، اینکه داخل بدنه متد مربوطه فقط میتوان از اعضای استاتیک کلاس استفاده کرد و نیز اعضایی که داخل خود متد به صورت غیر استاتیک تعریف میشوند ایزوله بوده و در فضای اشتراکی قرار داده نمیشوند و در این مورد نباید نگران در هم ریختگی اطلاعات کاربران همزمان سیستم بود. در واقع کلاس ها و متدها به صورت آبجکت هایی در فضای Heap یا Static قرار داده میشوند و به اعضای استاتیک و غیر استاتیکشان در فضای Stack یا Static از حافظه مرتبط میشوند.

 public class Employee
 {
 public string id;
 public string name;

 public Employee()
 {
 }

 public Employee(string name, string id)
 {
 this.name = name;
 this.id = id;
 }

 public static int employeeCounter;

 public static int AddEmployee()
 {
 return ++employeeCounter;
 }
 }


 چرا یک متد استاتیک نمیتواند از اعضای غیر استاتیک کلاس استفاده کنید؟
 به این دلیل که متد استاتیک قبل از نمونه سازی کلاس در دسترس است پس کلاس هنوز نمونه سازی نشده و فضایی به اعضای غیر استاتیک آن داده نشده که بخواهند در متد استاتیک ما مورد استفاده قرار گیرند.

 

نوشته شده توسط حامد شیربندی

اگر در مورد این نوشته سوال یا ابهامی وجود دارد میتوانید به ایمیل من ارسال کنید. البته در این مورد باید کمی صبور باشید. در آینده بخش نظرات اضافه خواهد شد.