در قسمت های قبلی (1 و
2 و
3 و
4 و
5) مطالب مفصلی راجع به قواعد نامگذاری ارائه شد. در ادامه، شرح نامگذاری اعضای یک نوع آورده میشه. تمامی انواع از اجزایی تشکیل شدن. این اجزا عبارتند از:
- نامهای انتخاب شده برای پارامترها باید کاملا توصیفی باشند.
- برای اپراتورهای تک پارامتری، اگه نشه نام مناسبی پیدا کرد باید از واژه value استفاده بشه. مثال:
- نباید از واژه های مخفف یا اندیس های عددی در نامگذاری این پارامترها استفاده کرد. مثلا مورد زیر نادرست است:
.: در ادامه به قواعد نامگذاری سایر اجزاء پرداخته میشه.
قسمت اول: کلیات
قسمت دوم: جزئیات
قسمت سوم: نامگذاری اسمبلی
قسمت چهارم: نامگذاری فضای نام
قسمت پنجم: نامگذاری نوع
قسمت ششم: نامگذاری اعضای نوع
:.
متد (method)
پراپرتی (property)
ایونت یا رویداد (event)
کانستراکتور یا سازنده (constructor)
فیلد (field)
برای نامگذاری هر یک از این اجزا، قواعد خاصی وجود داره که در ادامه بحث میشه.
چون متدها برای «انجام یک عملیات» استفاده میشن، نامشون حتما باید فعل یا عبارات فعلی باشه. اینکار موجب تفکیک آسونتر متدها از بقیه اجزاء میشه. درضمن مثل بیشتر اجزای یک برنامه، نام یک متد باید دقیقا مشخص کننده عملیاتی باشه که درونش انجام میشه.
این الگو به سادگی نشون میده که درصورت بوجود اومدن چنین حالاتی، پراپرتی باید به متد تبدیل بشه و درواقع استفاده از پراپرتی در چنین مواقعی کاملا اشتباهه.
- باید از مفاهیم با بار مثبت در نامگذاری پراپرتی های Boolean استفاده بشه. مثلا به جای CantPlay باید از CanPlay استفاده بشه.
- در مواردی که مناسب به نظر میرسه، بهتره که نام پراپرتی همنام با نوع مورد استفاده باشه. مثال:
نکته: ایجاد یک نوع delegate جدید بدینصورت برای هندلدر یک رویداد به ندرت نیاز میشه. به جای اون باید از نوع <EventHandler<TEventArgs استفاده بشه.
- برای پارامترهای متد هندلر رویداد باید از نامهای sender و e همونطور که در بالا نشون داده شده، به ترتیب برای نام ایجادکننده رویداد و آرگومانهای رویداد استفاده بشه.
- نام فیلد باید «اسم»، «عبارت اسمی» یا صفت باشه.
نامگذاری متدها
چون متدها برای «انجام یک عملیات» استفاده میشن، نامشون حتما باید فعل یا عبارات فعلی باشه. اینکار موجب تفکیک آسونتر متدها از بقیه اجزاء میشه. درضمن مثل بیشتر اجزای یک برنامه، نام یک متد باید دقیقا مشخص کننده عملیاتی باشه که درونش انجام میشه.
در نامگذاری متدها باید به وظیفه ای که داره توسط متد مربوطه انجام میشه دقت کرد و نه صرفا به پیاده سازی جاری اون. یعنی چی؟ خب، به یه مثال از طراحان دات نت فریمورک توجه کنین که این قاعده رو کامل توضیح دادن.
در یکی از مطالعات کاربری (ترجمه Usablitiy Study) برای کتابخونه System.Xml از شرکت کننده ها خواسته شده بود تا متدی برای اعمال یک کوئری روی نوع XPathDocument پیاده سازی کنن. برای اجرای این وظیفه لازم بود تا از متد CreateXPathNavigator از کلاس XPathDocument استفاد بشه. این متد یک نمونه از نوع XPathNavigator برمیگردونه که برای اجرای کوئری موردنظر بکار میره. اما در عمل هیچیکدوم از شرکت کنندگان موفق به شناسایی این متد و انجام درست پیاده سازی مربوطه نشدن، چون انتظار داشتن تا با متدی با نامی که شامل عباراتی مثل Query یا Select باشه کار کنن که انتظار درستی هم هست! چنین متدی میتونست وجود داشته باشه و به سادگی یک نمونه از XPathNavigator برگردونه با همون روشی که متد CreateXPathNavigator کار میکنه.
این مثال به خوبی نشون میده که چقدر این قاعده مهمه. در ضمن دقت کنین کسایی که تو این مطالعات شرکت میکنن عموما برنامه نویسای باتجربه ای هستن. این مثال نشون میده که استفاده از نام CreateXPathNavigator که بیشتر بر اساس نحوه پیاده سازی متد انتخاب شده نام نادرستیه. نام این متد باید بر اساس وظیفه ای که متد درواقع داره انجام میده و مفهومی آشنا و عمومی داره (برای نمونه تو این مورد خاص QueryDocument) استفاده بشه.
در یکی از مطالعات کاربری (ترجمه Usablitiy Study) برای کتابخونه System.Xml از شرکت کننده ها خواسته شده بود تا متدی برای اعمال یک کوئری روی نوع XPathDocument پیاده سازی کنن. برای اجرای این وظیفه لازم بود تا از متد CreateXPathNavigator از کلاس XPathDocument استفاد بشه. این متد یک نمونه از نوع XPathNavigator برمیگردونه که برای اجرای کوئری موردنظر بکار میره. اما در عمل هیچیکدوم از شرکت کنندگان موفق به شناسایی این متد و انجام درست پیاده سازی مربوطه نشدن، چون انتظار داشتن تا با متدی با نامی که شامل عباراتی مثل Query یا Select باشه کار کنن که انتظار درستی هم هست! چنین متدی میتونست وجود داشته باشه و به سادگی یک نمونه از XPathNavigator برگردونه با همون روشی که متد CreateXPathNavigator کار میکنه.
این مثال به خوبی نشون میده که چقدر این قاعده مهمه. در ضمن دقت کنین کسایی که تو این مطالعات شرکت میکنن عموما برنامه نویسای باتجربه ای هستن. این مثال نشون میده که استفاده از نام CreateXPathNavigator که بیشتر بر اساس نحوه پیاده سازی متد انتخاب شده نام نادرستیه. نام این متد باید بر اساس وظیفه ای که متد درواقع داره انجام میده و مفهومی آشنا و عمومی داره (برای نمونه تو این مورد خاص QueryDocument) استفاده بشه.
- نام متدها باید «فعل» یا «عبارات فعلی» باشه. مثال:
public class String { public int CompareTo( ... ); public string[] Split( ... ); public string Trim(); }
- نام متدها باید از روش Pascal Casing پیروی کنه.
نامگذاری پراپرتی ها
- با توجه ساختار و کاربرد خاصی که پراپرتی ها دارن، نامشون باید اسم یا صفت باشه. مثال:
public class String { public int Length { get; set; } }
- باید از روش Pascal Casing در نامگذاری پراپرتی ها استفاده بشه.
- نباید نام پراپرتی مشابه نام متدهای Get (اونایی که با واژه Get شروع میشن) انتخاب بشه. مثالهایی از این دو مورد در زیر آورده شده:
public string TextWriter { get { ... } set { ... } } public string GetTextWriter(int value) { ... }
- برای پراپرتی های مجموعه ای، باید از اسم جمع استفاده بشه. درواقع استفاده از یک نام مفرد و یک پسوند مثل List یا Collection در چنین مواردی نادرسته. مثال:
public class ListView { // نامگذاری درست public ItemCollection Items { get; } // نامگذاری نادرست public ItemCollection ItemCollection { get; } }
- باید از مفاهیم با بار مثبت در نامگذاری پراپرتی های Boolean استفاده بشه. مثلا به جای CantPlay باید از CanPlay استفاده بشه.
- برای پراپرتی های Boolean درصورتیکه مناسب باشه میشه از پیشوندهایی مثل Is یا Can یا Has استفاده کرد. دقت بشه که استفاده از پیشوندها تنها درصورتیکه نام نهایی تولید شده دارای معنی و مفهوم مناسب باشه توصیه میشه.
مثلا CanRead نام بسیار بهتری از Readable هست. اما Enabled از IsEnabled مناسبتر هست. در این موارد معمولا استفاده از پیشوند باعث طولانی شدن غیرضروری نام میشه، مخصوصا اگه کمک ابزارهایی مثال Intellisense در کار باشه. مثلا عبارت Control.Created بسیار روشنه و اگه Intellisense هم وارد بشه براحتی نوع این پراپرتی رو مشخص میکنه که کمک بزرگی به حساب میاد. البته با اینکه استفاده از نام IsCreated هم به نظر درست میاد اما با توجه به نکات اشاره شده، بکاربردن پیشوند Is در این مورد کاملا اضافیه.
برای انتخاب نام پراپرتی ها و متدهای Boolean برای آزمایش درستی نام انتخابی میشه از روش ifسنجی استفاده بشه. یعنی جزء موردنظر رو در یک عبارت if استفاده کرده و دید که آیا از لحاظ گرامری عبارت تولید شده ساختار درستی داره یا نه. مثلا:
بسیار مناسبتر و طبیعیتر از نمونه های زیرند:
if (collection.Contains(item)) if (regEx.Matches(text))
بسیار مناسبتر و طبیعیتر از نمونه های زیرند:
if (collection.IsContained(item)) if (regEx.Match(text))
- در مواردی که مناسب به نظر میرسه، بهتره که نام پراپرتی همنام با نوع مورد استفاده باشه. مثال:
public enum Color { ... } public class Control { public Color Color { get; set; } }
نامگذاری رویدادها
ایونت (رویداد یا رخداد) ها همیشه به اتفاقی که یا قراره رخ بده (در حال رخدادنده) یا قبلا رخ داده، اشاره دارن. بنابراین همچون متدها که به اجرای یک عملیات مربوطن، باید نامشون فعل یا عبارات فعلی با توجه به نوعشون (در حال رخدادن یا رخداده که در واقع مشخص کننده حالت رویداد هست) باشه.
- نام ایونتها باید «فعل» یا «عبارات فعلی» باشه. مثل Clicked یا Openning و Opened یا DroppedDown.
- نام رویدادها باید دارای مفهوم قبل یا بعد از رخدادن یک عمل باشه. این نامگذاری باید با استفاده از شکل حال استمراری و گذشته فعل انجام بشه. مثلا رویدادی که قبل از بسته شدن یک پنجره رخ میده باید Closing و رویدادی که بعدش رخ میده باید Closed نامگذاری بشه.
- نباید به هیچ وجه از پیشوندهای Before و After در نامگذاری رویدادها استفاده بشه.
- برای نامگذاری هندلر رویداد (delegate رویداد مربوطه) باید از پسوند EventHandler استفاده بشه. مثال:
public delegate void ClickedEventHandler(object sender, ClickedEventArgs e);
- برای نام نوع آرگومان رویداد باید از پسوند EventArgs استفاده بشه. مثال:
public class ClickedEventArgs : EventArgs { ... }
نامگذاری فیلدها
قواعدی که در ادامه این قسمت ارائه میشه تنها برای فیلدهای public و protected ضرورین. برای فیلدهای private و internal قواعد و دستورات اختیاری ای وجود داره که میشه از اونا پیروی نکرد و روش های مختلف دیگری رو پیاده کرد. البته این نکته مهم رو درنظر داشته باشین که در صورت استفاده از هر روشی باید در تمام پروژه و توسط تمام برنامه نویسا رعایت بشه.
درضمن ازوانجاکه قواعد طراحی اجازه استفاده از فیلدهای instance با دسترسی های عمومی (public و protected) رو نمیده، بنابراین قواعدی که در ادامه میاد تنها برای فیلدهای static عمومی ضروری هستند!
- باید از روش Pascal Casing در نامگذاری فیلدهای عمومی استفاده بشه. مثال:
public class String { public static readonly string Empty = ""; } public struct UInt32 { public const Min = 0; }
- نباید از پیشوند برای نام فیلد استفاده کرد.
مثلا نباید از پیشوندهایی مثل _g یا _s برای مشخص کردن فیلدهای استاتیک عمومی استفاده کرد. ازاونجاکه از لحاظ طراحی کتابخونه ها، فیلدهای عمومی استاتیک بسیار شبیه به پراپرتی ها هستند، بنابراین قواعد نامگذاری پراپرتی ها در نامگذاری این نوع فیلدها هم باید رعایت بشه.
نامگذاری پارامترها
واژه پارامتر در حالت کلی به آرگومانهای ورودی کلیه متدها (مثل کانستراکتور، اورلود اپراتور، ایندکس و ...) گفته میشه. علاوه بر افزایش خوانایی کد تولیدشده، رعایت قواعد نامگذاری پارامترها به دلیل نمایش این اعضا در اسناد کتابخونه ها و همچنین در استفاده از Intellisense ویژوال استودیو، کمک زیادی به آسونتر شدن استفاده از متدها میکنه و بسیار مهمه.
- باید از روش camelCasing در نامگذاری این پارامترها استفاده بشه. مثال:
public class String { public bool Contains(string value); public string Remove(int startIndex); }
این نامها باید دقیقا مشخص کننده کاربرد پارامتر باشن و برنامه نویس با تنها نگاه کردن به نام پارامتر براحتی بتونه به نوع و چگونوگی کاربرد اون برسه. این قاعده در زبونهایی که قابلیت named parameter دارن (مثل VB.NET و #C از نسخه 4.0 به بعد) اهمیت بیشتری هم داره.
- با توجه به توضیحات مقدماتی، بهتره نام پارامتر بر اساس معنی و مفهوم و کاربردش انتخاب بشه تا نوع داده پارامتر.
پارامترهای operator overload
- برای اپراتورهای باینری (دو پارامتری) اگه نشه نامهای با مفهوم درست و مختص کاربرد مربوطه پیدا کرد باید از واژه های left و right استفاده بشه. مثال:
public static TimeSpan operator-(DateTimeOffset left, DateTimeOffset right) public static bool operator==(DateTimeOffset left, DateTimeOffset right)
public static BigInteger operator-(BigInteger value)
- در حالت کلی، اگر استفاده از نامی به خصوص مفهوم بهتری داره، بهتره از اون به جای موارد پیشنهاد شده استفاده بشه. مثال:
public static BigInteger Divide(BigInteger divided, BigInteger divisor)
// نامگذاری نادرست پارامترهای اپراتور public static bool operator ==(DateTimeOffset d1, DateTimeOffset d2)
نامگذاری ریسورس (Resource) ها
ازاونجاکه نحوه استفاده از کلیدهای ریسورس (مثلا ریسورسهای localization) دقیقا مثل یک پراپرتیه، بنابراین قواعد نامگذاریشون شبیه هم هستش.
- باید از روش PascalCasing استفاده بشه.
- به جای استفاده از واژه های مختصر باید از نامهای کاملا توصیفی استفاده بشه. البته تا اونجا که میشه باید عبارت این نامهای توصیفی رو خلاصه کرد، اما در این عملیات نباید خوانایی رو فدای فضای استفاده شده کرد.
- نباید از واژه های کلیدی زبونهای اصلی CLR برای نام کلیدهای ریسورس استفاده کرد.
- باید تنها از حروف الفبایی، اعداد، و یا underscore استفاده بشه.
- برای نامگذاری کلید پیغام استثناها باید از قاعده زیر پیروی بشه:
نام کلید مربوطه باید از نام نوع استثنای مربوطه به همراه یک واژه معرف به عنوان پسوند تشکیل بشه. مثل:
ArgumentExceptionIllegalCharacters
ArgumentExceptionInvalidName
ArgumentExceptionFileNameMalformed
ArgumentExceptionInvalidName
ArgumentExceptionFileNameMalformed
.: در ادامه به قواعد نامگذاری سایر اجزاء پرداخته میشه.
قسمت اول: کلیات
قسمت دوم: جزئیات
قسمت سوم: نامگذاری اسمبلی
قسمت چهارم: نامگذاری فضای نام
قسمت پنجم: نامگذاری نوع
قسمت ششم: نامگذاری اعضای نوع
:.