نکات و اصول مهم در برنامه نویسی #C
1- حتی الامکان دایرکتیوهای using
رو بداخل namespace
منتقل کنید و در خارج از محدوده namespace رها نکنید.
StyleCop: SA1200: UsingDirectivesMustBePlacedWithinNamespace
namespace ConsoleApp1 { using System; using System.Collections.Generic; using System.Text; class Program { private static void Main(string[] args) { } } }
نکته: درصورتیکه فقط یک namespace
در فایل موردنظر موجود باشه.
2- همیشه reference های بلااستفاده رو از پروژه حذف کنید.
نکته: البته هنگام کامپایل برنامه، همه reference های استفاده نشده حذف میشن، ولی خب همیشه محیط کدنویسی رو تمیز و خلوت نگه دارید.
3- همیشه دایرکتیوهای using
بلااستفاده(خاکستری رنگ) رو از کلاسها حذف کنید.
using System.Drawing; using System.Resources; // <----- using System.Reflection; // <----- using System.Runtime.InteropServices; // <----- using System; using System.Windows.Forms;
4- جهت بازگشت چندین مقدار از یک متد میتونید از کلمه کلیدی ref
یا out
یا پرانتز (type1, type2, typeN) یا حتی Tuple
استفاده کنید:
public Tuple <int, string, string> GetStudent() { int studentId = 11; string firstName = "Alex"; string lastName = "Koertson"; return Tuple.Create(studentId, firstName, lastName); }
نکته: Tuple
از نوع reference type هستش و حداکثر ظرفیت 8 عنصر رو داره. همچنین از دات نت نسخه 4 و جدیدتر در دسترسه.
6- جهت نادیده گرفتن escapce character ها در رشته یا رفع خطای Unrecognized escape sequence می تونید از علامت @ در ابتدای شروع رشته استفاده کنید:
myStr = @"\\MyServer\TestFolder\NewFolder";
7- برای بدست اوردن مسیر جاری برنامه های WinForm، بهتره از Application.StartupPath
استفاده کنید و برای برنامه های Console بهتره از Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
استفاده کنید.
توجه: دستور Directory.GetCurrentDirectory
و AppDomain.CurrentDomain.BaseDirectory
و Environment.CurrentDirectory
به دلایل زیادی میتونن تغییر کنن و مسیر متفاوتی به شما بدن، همچنین دستور Path.GetDirectoryName(Environment.GetCommandLineArgs()[0])
در بعضی موارد نام و مسیر برنامه رو برگشت نمیده. پس برای بدست اوردن مسیرهای ثابت قابل اطمینان نیستن.
8- اگر از resources و settings در پروژه تون استفاده نمی کنید بهتره اونها رو حذف کنید:
9- درصورتیکه از قابلیت های غیر Common Language Specification / CLS در کدهاتون استفاده نمی کنید، خاصیت CLSCompliant
رو به فایل AssemblyInfo اضافه کنید:
[assembly: CLSCompliant(true)]
10- همیشه از language keywords(مثل int, string, float
) بجای base class type(مثل Int32, String, Single
) استفاده کنید.
11- جدول سازگاری بین نسخه های مختلف .Net:
12- چک لیست ساخت کلاس Utility:
1- کلاس باید static
باشد.
نکته: با اینکار کلاس بطور غیرصریح abstract
و sealed
خواهد بود. بنابراین عمل Inheritance و Instantiation صورت نخواهد گرفت. همچنین constructor و default constructor نخواهد داشت.
2- کلاس باید از شی Object
ارث برده باشد.
3- همه اعضای کلاس باید static
باشند.
13- آیا میدونید interpolation رشته در هنگام compile برنامه به String.Format
تبدیل میشه؟
یعنی کد:
string a = "Hello"; string b = $"{a} world";
بعد از compile برنامه تبدیل میشه به کد:
string a = "Hello"; string b = string.Format("{0} world", a);
14- نتیجه مقایسه سرعت پردازش رشته توسط String.Format
و StringBuilder
و +
کندترین String.Format
و سریعترین StringBuilder
15- نکته جزیی: آیا میدونید exception
های هندل/catch نشده بصورت خودکار به خروجی STDERR
فرستاده میشن؟
16- تنها زمانی باید از کلاس ResourceManager
استفاده کنید که قراره Resouce از نوع External رو داخل برنامه لود کنید.
17- سعی کنید همیشه تاریخ و زمان رو بر اساس UTC در فایل و دیتابیس ذخیره کنید و نه زمان محلی.
https://stackoverflow.com/questions/2532729/daylight-saving-time-and-time-zone-best-practices
https://stackoverflow.com/questions/2580478/storing-date-times-as-utc-in-database
و برای خوانایی و تبدیل بهتر میتونید از فرمت استاندارد ISO-8601 استفاده کنید. DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture);
18- نکته جزیی: فراموش نکنید که داده نوع NULL
همیشه یک مقدار Invalid/نامعتبر هستش و هرچیزی بجز NULL
یک مقدار Valid/معتبر هستش، حتی ""
19- تحت هیچ شرایطی مقدار NULL
رو return
نکنید. درعوض رشته خالی ""
یا 0 یا آرایه خالی []
بازگشت بدید.
20- هرگز از اعداد منفی برای تعیین Status/Exit code استفاده نکنید. از انجاییکه برای سیستم هر چیزی جز عدد 0 به FALSE
ترجمه میشه و بسیاری از زبانها قابلیت return
کردن اعداد منفی برای Status/Exit code رو ندارن، بهترین مقدار اعداد 0 یا مثبت هستن.
21- جدول تفاوت انواع Timer:
System.Windows.Forms | System.Timers | System.Threading | |
---|---|---|---|
Timer event runs on what thread? | UI thread | UI or worker thread | Worker thread |
Instances are thread safe? | No | Yes | No |
Familiar/intuitive object model? | Yes | Yes | No |
Requires Windows Forms? | Yes | No | No |
Metronome-quality beat? | No | Yes* | Yes* |
Timer event supports state object? | No | No | Yes |
Initial timer event can be scheduled? | No | No | Yes |
Class supports inheritance? | Yes | Yes | No |
(C) MSDN Magazine
22- نکته جزیی: در دنیای .Net واژه Entity درواقع همون Model یا POCO هستش که به یک Table در دنیای database اشاره داره.
23- مزایای استفاده از dependency injection در طراحی کلاس/متد:
- تمیز شدن کد و افزایش خوانایی کد
- آزاد شدن اتصالات و روابط کلاسها(loosely coupled)
- افزایش reusable شدن کد
- ساده شدن فرایند test کد
24- نکاتی راجب الگوهای طراحی DAO و Repository:
هردو object-oriented هستن
هردو زیر مجموعه Integration Tier Design Pattern هستن
هردو در لایه DAL یا persistence layer قرار دارن و برای پیاده سازی این لایه ها استفاده میشن
هردو میتونن Object یا دسته ای از Objects رو return کنن
هردو میتونن برای دور نگه داشتن application از تکنولوژی زیرساختی data source استفاده بشن(در واقع یک uniform data access API)
DAO به data source نزدیکتره اما Repository به application نزدیکتره
از DAO بیشتر برای دسترسی به Entities استفاده میشه و از Repository بیشتر برای سرهم کردن چند کلاس/خروجی DAO
از DAO برای مخفی سازی مباحث سطح پایین data source و پیچیدگی ها استفاده میشه
DAO معمولاً به data source vendor خاصی وابسته نیست
DAO معمولاً table محور هست اما Repository معمولاً Object محور
25- کاربردها و اهداف بلوک های static
:
- برای initialize کردن کدهای استاتیک(static) که هنگام Load شدن کلاس اعمال بشن
internal static Dictionary<String, String> myField = new Dictionary<String, String>(); static { myField.Add("Test name", "Test value"); // ... }
- برای initialize کردن کلاسهای master
public class MasterClass { static { SlaveClass.initialize(); // ... } }
توجه: باید فیلدهای static
در بلوک static
قرار بگیرند و initialize بشن و نه در constructor! اینها بخشی از class definition هستن و نه object.
26- سعی کنید متغیرهای کلاس رو در خارج از متد constructor آماده سازی/Initialize کنید. (اینها مقادیر پیشفرض دارن و حتی قبل از اینکه سازنده کلاس صدا زده بشه مقدار دهی می شوند. پس دوباره به اونها مقدار ندید. بعلاه خوانایی کلاس راحت تر و سریع تر انجام میشه)
27- همیشه هنگام توسعه نرم افزار، exception
ها و خطاها رو (در یک متغیر یا فایل) log کنید و توسط فرمی (با اجازه کاربر!) برای سرور/گیرنده خودتون ارسال کنید.
با اینکار یک سیستم bug report مناسب رو پیاده سازی کردید که بسیار به رفع اشکالات و بهبود برنامه تون کمک خواهد کرد.
28- هرگز بدون اجازه کابر، برنامه رو update نکنید.
29- هرگز بدون آگاهسازی کابر، اطلاعات اینترنتی رو دریافت و ارسال نکنید.
30- حتی الامکان از فراخوانی و کار با کلاس اشیا بصورت مستقیم در داخل حلقه ها خودداری کنید.
سعی کنید اونها رو به متغیرها انتقال بدید و بعد متغیر رو وارد حلقه کنید.
31- اصول طراحی کلاس:
- همیشه داده ها و فیلدها رو private
نگهدارید و از اصول encapsulation پیروی کنید.
- همیشه فیلدها رو initialize کنید.
- هرکلاس رو به یک نوع/دسته از داده اختصاص بدید.
- کلاسهای چند منظوره با چند مسئولیت طراحی نکنید، بلکه آنها را تجزیه و جداسازی کنید.
- بی دلیل برای همه فیلدها و داده ها accessor و mutator طراحی نکنید. (set/get
)
- همیشه بهترین و مناسبترین نام رو برای کلاس و متد تعیین کنید تا هدف رو بخوبی انعکاس بدهند.
- حتاالمکان کلاسها رو immutable (غیرقابل تغییر) طراحی کنید.
- بجای استفاده مکرر تودرتو if/else switch foreach
از interface
یا کلاس abstract
استفاده کنید.
- حتاالمکان کلاس رو static
طراحی نکنید. (بخاطر global state و مشکلات unit testing)
- از نوشتن متدهای طولانی و سنگین خودداری کنید. معمولاً متدهای طویل نشاندهنده رفتار و وظایف متعدد هستش که نیاز به تجزیه و refactoring داره.
- از قانون DRY (مخفف Don’t Repeat Yourself) پیروی کنید... متدهای تکراری رو با ساخت superclass abstract
یکی کنید.
32- همیشه تصاویر PNG پروژه رو توسط برنامه Image Tuner یا OptiPNG یا PNGCrush بهینه سازی کنید.
این برنامه ها قادرند header ها و metadata اضافی داخل فایل تصویر رو حذف و تصویر رو compress کنند.
https://github.com/imagemin/imagemin-cli
https://imageoptim.com/versions
https://pmt.sourceforge.io/pngcrush/
(Thanks to Elsa Ferreira )
https://websiteplanet.com/webtools/imagecompressor/
Mac OS:
https://github.com/ImageOptim/ImageOptim
https://nukesaq88.github.io/Pngyu/
https://pngquant.org/pngquant.tar.bz2
33- بجای استفاده از تصویر سیاه از رنگ سیاه #000000
استفاده کنید. بجای استفاده از تصویر سفید از رنگ سفید #FFFFFF
استفاده کنید و امثالش...
34- حتی الامکان بصورت مستقیم/directly فیلد های داخل اشیا رو فراخوانی کنید، بجای استفاده از پراپرتی و setter/getter
.
زمانی باید از setter/getter استفاده بشه که قراره عملیاتی بر روی فیلد مورد نظر انجام بشه.
35- مهمترین تفاوت الگوی Adapter و الگوی Facade:
- الگوی Adapter عمل تبدیل(convert) کلاس انجام میده اما الگوی Facade عمل ساده/خلاصه سازی(simplify) کلاس انجام میده.
- الگوی Adapter در نهایت یک کلاس رو پوشش میده اما الگوی Facade چندین کلاس رو پوشش میده.
36- نکته جزیی: پیشنهاد می کنم از تگ @todo
در XML doc comment استفاده نکنید... از انجایی که مستندات کدها عمومی هستند و برای کسب اطلاعات کلی طراحی شدند، محل مناسبی برای قرار دادن TODO های پروژه نیستند.
37- نکته جزیی: همیشه در آخر هر فایل یک خط خالی(blank line) قرار بدید. بعضی از ویرایشگر ها بجای بررسی EOF، خط آخر رو ignore می کنند. (در همه زبانها)
38- آیا میدونید Constructor ها متد نیستند و فقط class type رو بازگشت میدن؟
class Vehicle { public Vehicle() // Constructor { } public void vehicle() // Method! { // print 123 } } Vehicle Saloons = new Vehicle(); // Construct Saloons.vehicle(); // Method call
حتی درصورت عدم وجود Constructor، کامپایلر یک Constructor بدون پارامتر، همنام کلاس شما تولید میکنه...
39- یادتون باشه که تنها دلیل استفاده از ابزارهای اتوماسیون build(مثل MSBuild, NAnt, Cake, Ant) فقط کاهش خطاهای انسانی و صرفه جویی در زمان هستش.
40- توسط ابزار nukeeper یا dotnet-outdated می تونید بصورت خودکار پکیج های NuGet پروژه یا سیستم رو بروزرسانی کنید.
اگر قبلا در بیان ثبت نام کرده اید لطفا ابتدا وارد شوید، در غیر این صورت می توانید ثبت نام کنید.