۱۳۸۸/۰۶/۲۸

بررسي واژه كليدي static


تفاوت بين يك كلاس استاتيك، متدي استاتيك و يا متغير عضو استاتيك چيست؟ چه زماني بايد از آن‌ها‌ استفاده كرد و لزوم بودن آن‌ها‌ چيست؟
براي پاسخ دادن به اين سؤالات بايد از نحوه‌ي تقسيم بندي حافظه شروع كرد.
RAM براي هر نوع پروسه‌اي كه در آن بارگذاري مي‌شود به سه قسمت تقسيم مي‌گردد: Stack ، Heap و Static (استاتيك در دات نت در حقيقت قسمتي از Heap است كه به آن High Frequency Heap نيز گفته مي‌شود).
اين قسمت استاتيك حافظه، محل نگهداري متدها و متغيرهاي استاتيك است. آن متدها و يا متغيرهايي كه نياز به وهله‌اي از كلاس براي ايجاد ندارند، به صورت استاتيك ايجاد مي‌گردند. در سي شارپ از واژه كليدي static براي معرفي آن‌ها كمك گرفته مي‌شود. براي مثال:

class MyClass
{
public static int a;
public static void DoSomething();
}
در اين مثال براي فراخواني متد DoSomething نيازي به ايجاد يك وهله جديد از كلاس MyClass نمي‌باشد و تنها كافي است بنويسيم:

MyClass.DoSomething(); // and not -> new MyClass().DoSomething();
نكته‌ي مهمي كه در اينجا وجود دارد اين است كه متدهاي استاتيك تنها قادر به استفاده از متغيرهاي استاتيك تعريف شده در سطح كلاس هستند. علت چيست؟
به مثال زير دقت نمائيد:

class MyClass
{
// non-static instance member variable
private int a;
//static member variable
private static int b;
//static method
public static void DoSomething()
{
//this will result in compilation error as “a” has no memory
a = a + 1;
//this works fine since “b” is static
b = b + 1;
}
}
در اين مثال اگر متد DoSomething را فراخواني كنيم، تنها متغير b تعريف شده، در حافظه حضور داشته (به دليل استاتيك معرفي شدن) و چون با روش فراخواني MyClass.DoSomething هنوز وهله‌اي از كلاس مذكور ايجاد نشده، به متغير a نيز حافظه‌اي اختصاص داده نشده است و نامعين مي‌باشد.
بر اين اساس كامپايلر نيز از كامپايل شدن اين كد جلوگيري كرده و خطاي لازم را گوشزد خواهد كرد.

اكنون تعريف يك كلاس به صورت استاتيك چه اثري را خواهد داشت؟
با تعريف يك كلاس به صورت استاتيك مشخص خواهيم كرد كه اين كلاس تنها حاوي متدها و متغيرهاي استاتيك مي‌باشد. امكان ايجاد يك وهله از آن‌ها وجود نداشته و نيازي نيز به اين امر ندارند. اين كلاس‌ها امكان داشتن instance variables را نداشته و به صورت پيش فرض از نوع sealed به حساب خواهند آمد و امكان ارث بري از آن‌ها نيز وجود ندارد. علت اين امر هم اين است كه يك كلاس static هيچ نوع رفتاري را تعريف نمي‌كند.

پس با اين تفاسير چرا نياز به يك كلاس static ممكن است وجود داشته باشد؟
همانطور كه عنوان شد يك كلاس استاتيك هيچ نوع رفتاري را تعريف نمي‌كند بنابراين بهترين مكان است براي تعريف متدهاي كمكي كه به ساير اعضاي كلاس‌هاي ما وابستگي نداشته، عمومي بوده، مستقل و متكي به خود هستند. عموما متدهاي كمكي در يك برنامه به صورت مكرر فراخواني شده و نياز است تا به سرعت در دسترس قرار داشته باشند و حداقل يك مرحله ايجاد وهله كلاس در اينجا براي راندمان بيشتر حذف گردد.
براي مثال متدي را در نظر بگيريد كه بجز اعداد، ساير حروف يك رشته را حذف مي‌كند. اين متد عمومي است، وابستگي به ساير اعضاي يك كلاس يا كلاس‌هاي ديگر ندارد. بنابراين در گروه متدهاي كمكي قرار مي‌گيرد. اگر از افزونه‌ي ReSharper‌ استفاده نمائيد، اين نوع متدها را به صورت خودكار تشخيص داده و راهنمايي لازم را جهت تبديل آ‌ن‌ها به متد‌هاي استاتيك ارائه خواهد داد.

با كلاس‌هاي استاتيك نيز همانند ساير كلاس‌هاي يك برنامه توسط JIT compiler رفتار مي‌شود، اما با يك تفاوت. كلاس‌هاي استاتيك فقط يكبار هنگام اولين دسترسي به آن‌ها ساخته شده و در قسمت High Frequency Heap حافظه قرار مي‌گيرند. اين قسمت از حافظه تا پايان كار برنامه از دست garbage collector‌ در امان است (بر خلاف garbage-collected heap‌ يا object heap كه جهت instance classes مورد استفاده قرار مي‌گيرد)


نكته:
در برنامه‌هاي ASP.Net از بكارگيري متغيرهاي عمومي استاتيك برحذر باشيد (از static fields و نه static methods). اين متغيرها بين تمامي كاربران همزمان يك برنامه به اشتراك گذاشته شده و همچنين بايد مباحث قفل‌گذاري و امثال آن‌را در محيط‌هاي چند ريسماني هنگام كار با آن‌ها رعايت كرد (thread safe نيستند).