PDA

View Full Version : چند نکته برای برنامه نویسی بهتر در #C



بابک زواری
یک شنبه 12 تیر 1384, 14:41 عصر
نویسنده :‌داریوش تصدیقی

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

- مسوولین مایکروسافت تاکید دارند در صورتیکه تداخلی (Conflict) در بکارگیری کلاس ها وجود نداشته باشد، همیشه فضاهای نامی (Namespace) را در بالای صفحات، با استفاده از کلمه Using مشخص نماییم. البته این گفته تا حدودی نیز صحیح می باشد و شاید اکثر دوستان نیز این قاعده را رعایت کرده و می کنند و اکثرا در بالای صفحات خود با عباراتی مانند نمونه های ذیل برخورد کرده اند:



Using System;
Using System.Windows.Forms;
ولی نظر اینجانب کاملا متفاوت است! اگر تمامی نمونه برنامه های اینجانب را چه در پروژه های در مقیاس کوچک و یا متوسط مشاهده نمایید، خواهید دید که حتی یک Using نیز در بالای صفحات وجود ندارد! علت این است که هر چند با توجه به پیشنهاد مایکروسافت، از نوشته شدن سورس کد اضافی، اجتناب می شود، ولی یادگیری فضاهای نامی کلاسهای پرکاربرد مایکروسافت، به شدت دچار اشکال می شود. اجازه دهید نمونه ای را مطرح نمایم. بارها مشاهده شده است که برنامه نویسان، برای حل مشکلی، نمونه سورس کدی را از اینترنت بدست می آورند و از آنجاییکه اکثر برنامه نویسان بی حوصله هستند، مگر خلاف آن ثابت شود! از کل سورس کد، تنها قسمت کوچکی را که تمایل دارند، کپی نموده و در برنامه خود Paste می کنند. زمانیکه برنامه را Compile می کنند، با هزاران خطا مواجه می شوند! و چون حوصله جستجو در اینترنت و MSDN را برای یافتن فضاهای نامی مناسب ندارند، کل فضاهای نامی سورس کد اولیه را کپی کرده و سورس کد خود را با حجمی بیهوده از فضاهای نامی مزین می کنند! تجربه ای که اینجانب و دیگر دوستانم در حذف تمامی فضاهای نامی به روش معمول داشته ایم، این بوده است که به لطف خداوند و به مرور زمان، تقریبا روی اکثر فضاهای نامی پرکاربرد مسلط شده و در این راستا با کلاسها و فضاهای نامی مفید دیگری نیز در حین کار آشنا شده ایم. لذا از این پس در تمامی سورس کدهایی که تقدیم حضور خواهد شد، هیچ گونه فضای نامی به گونه متعارف استفاده نخواهد شد!

- شاید خیلی از دوستان، قبل از برنامه نویسی با زبان های شیء گرا خصوصا #C با زبان های برنامه نویسی Structured مانند Foxpro و یا Event Oriented مانند Visual Basic و غیره آشنایی داشته باشند. در آن زبانها بسیار اتفاق افتاده است که برنامه نویسان تمایل داشته باشند تا قسمت هایی از سورس کد خود را در داخل یک زیر برنامه (Sub Routine) نوشته و در مکانهای مناسبی صدا (Call) نمایند. این تفکر کماکان با حفظ احتیاط در زبان های برنامه نویسی شیء گرا نیز قابل پیاده سازی می باشد. تعجب نکنید! تصور نکنید که برای هر کاری در زبانهای برنامه نویسی شیء گرا باید کلاسی خلق کرده و از آن شیئی ایجاد کرده تا بتوانید تابعی (متدی) از آنرا اجرا نمایید!. در زبان برنامه نویسی #C، شما می توانید کلاسی ایجاد کرده و در آن متد و یا متدهایی به صورت استاتیک (Static) تعریف نمایید. متدهای استاتیک مربوط به خود کلاس بوده و اساسا ارتباطی با اشیاء کلاس ندارند. لذا شما می توانید از طریق خود کلاس، تابع استاتیک مربوطه را اجرا نمایید. در صورتی که با Console Application کار کرده باشید، به کرات با دستوراتی به شکل ذیل مواجه شده اید:


System.Console.WriteLine("Hello World!");
در نمونه فوق، در فضای نامی System، کلاسی به نام Console وجود دارد که در داخل آن تابع استاتیکی به نام WriteLine در نظر گرفته شده است. در نمونه فوق شما نیازی به ایجاد شیئی از نوع کلاس Console برای به اجرا درآوردن تابع WriteLine ندارید!

با توجه به مطالب فوق، شاید در یک پروژه واقعی ایجاد توابعی که چندان ارتباطی با مفهوم کلاس و شیء و غیره ندارند، بسیار ضروری باشد. ما اینگونه پیشنهاد می کنیم:

معمولا بهتر است که در هر پروژه یک کلاس با نام Globals و یا Publics و یا Utilities به شکل ذیل تعریف نمایید:


public sealed class Utilities
{
private Utilities(){}
}

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


public sealed class Utilities
{
private Utilities(){}

public static bool CreateFolder(string pathName)
{
bool blnResult = true;

return(blnResult);
}
}
در تکمیل مطالب فوق، عنوان چند نکته ضروری می باشد:

اول آنکه در تعریف این کلاس، از کلمه sealed استفاده شده است. بکارگیری این کلمه بدین معنی است که از این کلاس نمی توان Inherit کرد، که بدیهی است ارث بری از چنین کلاسی که تنها با یک سری توابع استاتیک تعریف شده است، چندان کار عاقلانه ای نباشد.
دوم آنکه سازنده (Constructor) این کلاس به صورت Private تعریف شده است. علت این امر آن است که ما نه تنها تمایل نداریم بلکه به طور کلی معنی ندارد که کاربر (کسی که از این Library استفاده می کند) بتواند از این کلاس شیئی بسازد.

- یکی از مواردی که شاید در برنامه نویسی مفید باشد، ایجاد کلاس ها در فضاهای نامی مناسب و لایه ای است، که البته در این زمینه اختلاف نظرهایی نیز وجود دارد. اجازه دهید موضوع را با یک مثال توضیح دهیم. فرض کنید که می خواهیم یک Library در رابطه با مدیریت فایل ها و پوشه ها مانند ایجاد پوشه، تغییر نام پوشه، حذف پوشه و غیره ایجاد نماییم و تصور کنید که برای انجام این عمل، به کلاسی با نام Utilities به شکل تعریف شده در مطلب قبلی نیاز داشته باشیم. حال سوال این است که این کلاس را در چه فضای نامی تعریف نماییم:

راه حل اول: برخی بر این عقیده اند، برای اینکه بکارگیری Library آسان تر باشد، بهتر است در همان فضای نامی که مایکروسافت تعریف کرده است، مشخص شود:


namespace System.IO
{
public sealed class Utilities
{
private Utilities(){}

public static bool CreateFolder(string pathName)
{
bool blnResult = true;

return(blnResult);
}
}
}
یکی از مزیت هایی که در این روش مستتر می باشد این است که کاربری که سالها با فضای نامی System.IO کار کرده، برای استفاده از کلاس Utilities شما، دیگر نیازی به مطالعه فضاهای نامی که در مستندات خود مشخص کرده اید، نخواهد داشت! و به راحتی می تواند در قسمت های مختلف برنامه، از کلاس شما استفاده نماید:


System.IO.Utilities.CreateFolder("C:\\Temp");
راه حل دوم: راه حل دوم نیز بی شباهت به راه حل اول نمی باشد، در این روش به جای استفاده از کلمه System از نام شخص یا شرکت سازنده استفاده می شود و به ازای هر یک از لایه های فضای نامی یک پوشه در ریشه پروژه ایجاد می شود. به عنوان نمونه تصور کنید که شرکت ایران خودرو تمایل دارد که یک Library به شکل فوق ایجاد نماید. در این صورت ابتدا در ریشه پروژه، یک پوشه به نام IranKhodro ایجاد کرده و در داخل آن پوشه دیگری به نام IO ایجاد می نماید و سپس در داخل پوشه IO کلاسی به شکل ذیل ایجاد می نماید:


namespace IranKhodro.IO
{
public sealed class Utilities
{
private Utilities(){}

public static bool CreateFolder(string pathName)
{
bool blnResult = true;

return(blnResult);
}
}
}
در این نمونه نیز کاربر به راحتی می تواند با سابقه ذهنی که از فضاهای نامی مایکروسافت دارد و تنها با جایگزینی کلمه System به IranKhodro به تابع مورد نظر خود دسترسی پیدا کند:


IranKhodro.IO.Utilities.CreateFolder("C:\\Temp");
که البته اینجانب به شخصه، روش دوم را بیشتر می پسندم.

- شرمنده! می دانم که خسته شده اید!! ولی یه چند لحظه تحمل کنید تا این نکته آخر را نیز خاطر نشان نمایم. به عنوان حسن ختام، پیشنهاد می کنم که تمامی توابعی که تعریف می کنید، چه توابعی که به صورت استاتیک تعریف می کنید و چه توابعی که به صورت غیر استاتیک تعریف می نمایید، باید (بهتر است) به صورت امری تعریف کرده و با یک فعل آغاز نمایید. این مطلب در ادبیات شیء گرایی بسیار حائز اهمیت می باشد. به عنوان نمونه بکارگیری توابعی که با کلماتی همچون Get, Put, Set و غیره آغاز می شوند، بسیار مناسب تر می باشد.



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

- هرچند که در زمان طراحی و پیاده سازی کلاسها، امکان تعریف فیلدهای Public وجود دارد، ولی به عنوان یک برنامه نویس حرفه ای به هیچ وجه از فیلدهای Public استفاده ننمایید!. حال ممکن است از خود سوال نمایید که چگونه می توان فیلدهای Public را شبیه سازی نمود؟ بسیار ساده است! شما بهتر است فیلدهایی را که می خواهید Public تعریف نمایید، به صورت Private تعریف نموده و برای قابل دسترس بودن آنها به طور متناظر از Property استفاده نمایید:

روش نادرست:


public int Age;
روش صحیح:



private int _age;

public int Age
{
get
{
return(_age);
}
set
{
_age = value;
}
}
توجه: دلایل عدم استفاده از فیلدهای Public بسیار زیاد می باشد و از حوصله این مقاله خارج است.

- یکی دیگر از مواردی که در زمان طراحی و پیاده سازی کلاس ها حائز اهمیت می باشد، نحوه نامگذاری متغیرها می باشد. البته لازم به ذکر است که استانداردهای متفاوتی در این زمینه وجود دارد که شخصا استاندارد ذیل را مطلوب تر ارزیابی کرده و بسیار علاقه مندم که دیگر دوستان، ما را با استانداردهای دیگری نیز آشنا نمایند. استانداردی که در ذیل عنوان خواهد شد، یکی از استانداردهای استفاده شده در زبان برنامه نویسی Java بوده که طبعا بکارگیری آن در زبان برنامه نویسی #C، خالی از لطف نمی باشد:

1- در این استاندارد، اسامی فیلدهای Public و Property ها با حرف اول بزرگ آغاز شده و بقیه حروف، به صورت کوچک نوشته می شوند. مانند کلمات: Age و FullName

دقت کنید که اگر نام فیلد مانند FullName از چند کلمه تشکیل شده باشد، قاعده مذکور در مورد هر کلمه صادق می باشد.

2- فیلدهای Private و Protected مانند فیلدهای Public و Property ها بوده و تنها تفاوت آنها این است که حرف اول، اولین کلمه آن با حروف کوچک آغاز گردد و قبل از آن از Underline استفاده می شود. مانند کلمات: age_ و fullName_

3- پارامترهای ورودی توابع نیز مانند فیلدهای Public و Property ها تعریف شده و تنها کافی است که حرف اول، اولین کلمه آن با حروف کوچک آغاز گردد. مانند کلمات: age و fullName

4- متغیرهای تعریف شده در داخل توابع و Block ها نیز مانند فیلدهای Public و Property ها تعریف شده و تنها کافی است که مشخصه یا نوع آنها، ترجیحا با سه حرف کوچک در قبل از آنها قرار بگیرد. مانند کلمات: intAge و strFullName

نمونه ذیل را با هم می بینیم:




public class Person
{
private string _fullName;

public string FullName
{
get
{
return(_fullName);
}
set
{
_fullName = value;
}
}

public Person(string fullName)
{
string strFullName = "Dariush Tasdighi!";

if(fullName == "")
FullName = strFullName;
else
FullName = fullName;
}
}

vDelphi
چهارشنبه 15 تیر 1384, 01:15 صبح
:flower: :موفق:

afsar
چهارشنبه 15 تیر 1384, 06:01 صبح
:flower:

Kamran.K
چهارشنبه 15 تیر 1384, 10:30 صبح
مرسی
در مورد بخش اول بنده ترجیح می‌دهم کدی که می‌نویسم خلوت تر باشد. لذا در مورد "فضانام‌های" پرکاربرد از using استفاده می‌کنم و در فقط در مواردی که از فضانامی استفاده شود که کم‌تر استفاده شود، یا فضانام‌هایی که توسط خودمان تولید شده‌اند از نام کامل استفاده می‌کنم.


از آنجاییکه اکثر برنامه نویسان بی حوصله هستند، کل فضاهای نامی سورس کد اولیه را کپی کرده و سورس کد خود را با حجمی بیهوده از فضاهای نامی مزین می کنند!
برای جلوگیری از این گونه مزین کاری ها کافی است امور را به ReSharper بسپارید. این AddIns پس از نصب، همچنان که شما کد می‌نویسید، کدهای شما را تحلیل کرده و پیشنهادهای مناسبی را ارائه می‌دهد.
از جمله حذف فضانام‌های بدون استفاده (فقط با یک کلیک)، حذف متغیرهای بدون استفاده و ...
البته ویژگیهای دیگری نیز دارد که چون خارج از بحث هستش اشاره نمی‌کنم.

اضافه شد:
<span dir=ltr>http://www.jetbrains.com/resharper/</span>

Beyondsoft
پنج شنبه 06 مرداد 1384, 12:41 عصر
به نظر من اصلا کار خوبی نیست که زیاد از namespace استفاده کرد
چون در جایی وقت ها تداخل پیش می آید
به طور مثال دو تابع مختلف که یک نام دارند در namespace ها مختلف وجود دارد
که با این کار می شکل پیش می آید .

M.GhanaatPisheh
پنج شنبه 06 مرداد 1384, 14:10 عصر
راه عاقلانه همونیه که کامران کمایی گفت :

""لذا در مورد "فضانام‌های" پرکاربرد از using استفاده می‌کنم و در فقط در مواردی که از فضانامی استفاده شود که کم‌تر استفاده شود، یا فضانام‌هایی که توسط خودمان تولید شده‌اند از نام کامل استفاده می‌کنم""

سلماس
دوشنبه 15 اسفند 1384, 21:00 عصر
خیلی خوب بود ممنون

Milad Mohseny
سه شنبه 16 اسفند 1384, 00:31 صبح
باز هم مثل همیشه کار آقای زواری خیلی درسته

Semir
سه شنبه 16 اسفند 1384, 01:00 صبح
سلام
خیلی جالب بود.
ممنون

محمد میرمصطفی
سه شنبه 16 اسفند 1384, 01:49 صبح
استاد تصدیقی، استاد من هستند و من بارها سر کلاسهای حضوری ایشون حاضر شدم.
نظرات زیر صرفا شخصی هستن من قصد توهین ندارم پیشاپیش گه کدورتی پیش اومد من معذرت می‏خوام.

زمانیکه برنامه را Compile می کنند، با هزاران خطا مواجه می شوند!
در C# 2.0 این مشکل حل شده و خود IDE باهوش usingها رو ست می‏کنه پس از این بابت نگرانی نداریم.

در تعریف این کلاس، از کلمه sealed استفاده شده است.
لزومی نداره. من ترجیح می‏دم از private ctor استفاده کنم و بجای sealed از static. چون حداقل یه حسن بزرگ داره. گاهی واسم پیش اومده که اشتباها از کلمه static قبل از تعریف متد استفاده نکردم. و تو source با تعجب دیدم که متدم تو Intellisense نمیاد. ولی با static کردن کلاس، خود کامپایلر به این موضوع گیر می‏ده.

بهتر است فیلدهایی را که می خواهید Public تعریف نمایید، به صورت Private تعریف نموده و برای قابل دسترس بودن آنها به طور متناظر از Property استفاده نمایید
این گفته انصافا عالیه. من حداقل 5 دلیل خیلی محکم دارم.
با تشکر.

once4ever
سه شنبه 16 اسفند 1384, 10:59 صبح
مفیدبود


بهتر است فیلدهایی را که می خواهید Public تعریف نمایید، به صورت Private تعریف نموده و برای قابل دسترس بودن آنها به طور متناظر از Property استفاده نمایید

میشه چندتا از دلیلهارو بفرمایید.

محمد میرمصطفی
چهارشنبه 17 اسفند 1384, 12:09 عصر
The primary use of a field should be as an implementation detail. Fields should be private or internal and should be exposed by using properties. Accessing a property is as easy as accessing a field, and the code in a property's accessors can change as the type's features expand without introducing breaking changes. Properties that just return the value of a private or internal field are optimized to perform on par with accessing a field; there is no performance gain associated with using externally visible fields over properties.
Externally visible refers to public, protected, and protected internal (Public, Protected, and Protected Friend in Visual Basic) accessibility levels.


Externally visible fields do not provide any benefits that are unavailable to properties. Additionally, public fields cannot be protected by Link Demands.

barnamenevisjma
سه شنبه 02 آذر 1389, 15:08 عصر
من ترجیح می‏دم از private ctor استفاده کنم

میشه در مورد این کمی توضیح بدین.
مرسی