قراردادهای کدنویسی #C (راهنمای برنامه‌نویسی #C)

هر زبان برنامه‌نویسی دارای قراردادهای خاص خود است. زبان #C نیز قراردادهایی دارد. دستورالعمل‌های این قراردادها توسط مایکروسافت برای توسعه نمونه‌ها و مستندات مورد استفاده قرار می‌گیرد. در این مقاله این قراردادها را بررسی می‌کنیم.

قراردادهای کدنویسی #C (راهنمای برنامه‌نویسی #C)

قراردادهای برنامه‌نویسی اهداف زیر را دنبال می‌کنند:

آن‌ها نگاهی پایدار به کد ایجاد می‌کنند، تا خوانندگان بتوانند بر روی محتوا، نه طرح‌بندی، تمرکز کنند.

آن‌ها خوانندگان را قادر می‌سازند تا با ساختن فرضیاتی بر پایه تجربه قبلی، کد را سریع‌تر درک کنند.

آن‌ها کپی، تغییر و نگهداری کد را آسان می‌سازند.

آن‌ها بهترین شیوه‌های #C را نشان می‌دهند.

قراردادهای نام‌گذاری

در نمونه‌های کوتاهی که شامل استفاده از دستورالعمل‌ها نیستند، از شرایط فضای نام‌ها استفاده کنید. اگر می‌دانید که یک فضای نامی به طور پیش‌فرض در پروژه وارد شده است مجبور نیستید نام آن فضای نام را به طور کامل بیان کنید. نام‌های واجد شرایط اگر طولانی بوده و بیش از یک خط شوند می‌توانند بعد از دات (.) شکسته شوند، همان‌طور که در مثال زیر نشان داده شده است.

var currentPerformanceCounterCategory = new System.Diagnostics.
    PerformanceCounterCategory();

لازم نیست نام‌های اشیایی که با استفاده از ابزارهای طراحی ویژوال استودیو ساخته شده‌اند را تغییر دهید تا آن‌ها را متناسب با دستورالعمل‌های دیگر قرار دهید.

قراردادهای طرح‌بندی

طرح‌بندی خوب از قالب‌بندی برای تأکید بر ساختار کدتان و ایجاد کدی که ساده‌تر خوانده می‌شود استفاده می‌کند. مثال‌ها و نمونه‌های مایکروسافت از قراردادهای زیر پیروی می‌کنند:

از تنظیمات پیش‌فرض ویرایشگر کد مانند تورفتگی‌های هوشمند استفاده کنید.

فقط یک توضیح در هر خط بنویسید.

فقط یک اعلان در هر خط بنویسید.

اگر خطوط پشت سر هم به صورت خودکار تورفتگی نداشته باشند، تورفتگی را برای آن‌ها با فشردن تب ایجاد کنید (four spaces).

حداقل یک خط خالی بین تعاریف متدها و تعاریف ویژگی‌ها اضافه کنید.

با استفاده از پرانتزها شرط را در یک عبارت مشخص ایجاد کنید، همان‌طور که در کد زیر نشان داده شده است.

if ((val1 > val2) && (val1 > val3))
{
    // Take appropriate action.
}

قراردادهای کامنت‌گذاری (توضیحات)

کامنت را در یک خط جداگانه قرار دهید، نه در انتهای خط کد.

متن کامنت را با حرف بزرگ شروع کنید.

متن کامنت را با یک نقطه به پایان برسانید.

یک فاصله بین علامت‌های کامنت (//) و متن کامنت بگذارید، همان‌طور که در مثال زیر نشان داده شده است.

// The following declaration creates a query. It does not run
// the query.

بلوک‌های قالب‌دار را که دارای نشان ستاره در اطراف کامنت هستند را نسازید.

دستورالعمل‌های زبان

بخش‌های زیر عملکردهایی را توصیف می‌کنند که تیم #C آن‌ها را برای مثال‌ها و نمونه کدها دنبال می‌کند.

نوع داده رشته

از عملگر + برای الحاق رشته‌های کوتاه استفاده کنید، همان‌طور که در کد زیر نشان داده شده است.

string displayName = nameList[n].LastName + ", " + nameList[n].FirstName;

برای افزودن رشته‌ها در حلقه‌ها، به ویژه هنگامی که با مقادیر زیادی از متن‌ها کار می‌کنید، از شیء StringBuilder استفاده کنید.

var phrase = "lalalalalalalalalalalalalalalalalalalalalalalalalalalalalala";
var manyPhrases = new StringBuilder();
for (var i = 0; i < 10000; i++)
{
    manyPhrases.Append(phrase);
}
//Console.WriteLine("tra" + manyPhrases);

تعریف ضمنی متغیرهای محلی

زمانی که نوع متغیر در سمت راست که به آن تخصیص داده شده است مشخص می‌باشد یا زمانی که نوع دقیق مهم نیست، از نوشتن ضمنی برای متغیرهای محلی استفاده کنید.

// When the type of a variable is clear from the context, use var 
// in the declaration.
var var1 = "This is clearly a string.";
var var2 = 27;
var var3 = Convert.ToInt32(Console.ReadLine());

وقتی نوعی که در سمت راست اختصاص داده شده است مشخص نیست، از var استفاده نکنید.

// When the type of a variable is not clear from the context, use an
// explicit type.
int var4 = ExampleClass.ResultSoFar();

برای تعیین نوع متغیر به نام آن اعتماد نکنید. ممکن است درست نباشد.

// Naming the following variable inputInt is misleading. 
// It is a string.
var inputInt = Console.ReadLine();
Console.WriteLine(inputInt);

از استفاده var در موقعیت‌های داینامیک اجتناب کنید.

از نوع ضمنی برای مشخص کردن نوع متغیر حلقه در حلقه‌های for و foreach استفاده کنید.

مثال زیر از یک نوع ضمنی برای for استفاده کرده است.

var syllable = "ha";
var laugh = "";
for (var i = 0; i < 10; i++)
{
    laugh += syllable;
    Console.WriteLine(laugh);
}

مثال زیر از یک نوع ضمنی برای foreach استفاده کرده است.

foreach (var ch in laugh)
{
    if (ch == 'h')
        Console.Write("H");
    else
        Console.Write(ch);
}
Console.WriteLine();

نوع داده Unsigned (اعداد بزرگتر از صفر)

به طور کلی، از int به جای انواع Unsigned استفاده کنید. استفاده از int در #C رایج است و هنگامی که از آن استفاده می‌کنید به راحتی می‌‌توانید با کتابخانه‌های دیگر ارتباط برقرار کنید.

آرایه‌ها

هنگام مقداردهی اولیه آرایه‌ها در خط اعلان، از سینتکس کوتاه و مختصر استفاده کنید.

// Preferred syntax. Note that you cannot use var here instead of string[].
string[] vowels1 = { "a", "e", "i", "o", "u" };


// If you use explicit instantiation, you can use var.
var vowels2 = new string[] { "a", "e", "i", "o", "u" };

// If you specify an array size, you must initialize the elements one at a time.
var vowels3 = new string[5];
vowels3[0] = "a";
vowels3[1] = "e";
// And so on.

Delegateها

برای ایجاد نمونه‌هایی از نوع delegate از سینتکس کوتاه و مختصر استفاده کنید.

// First, in class Program, define the delegate type and a method that  
// has a matching signature.

// Define the type.
public delegate void Del(string message);

// Define a method that has a matching signature.
public static void DelMethod(string str)
{
    Console.WriteLine("DelMethod argument: {0}", str);
}
// In the Main method, create an instance of Del.

// Preferred: Create an instance of Del by using condensed syntax.
Del exampleDel2 = DelMethod;

// The following declaration uses the full syntax.
Del exampleDel1 = new Del(DelMethod);

try-catch و استفاده از بیانیه‌ها در مدیریت Exception

از try-catch برای بیشتر exceptionها (خطاها) استفاده کنید.

static string GetValueFromArray(string[] array, int index)
{
    try
    {
        return array[index];
    }
    catch (System.IndexOutOfRangeException ex)
    {
        Console.WriteLine("Index is out of range: {0}", index);
        throw;
    }
}

کد خود را با استفاده از دستور using در #C ساده کنید. اگر یک try-finally دارید که تنها کد موجود در بلوک finally یک متد Dispose را فراخوانی می‌کند، به جای آن از using استفاده کنید.


// This try-finally statement only calls Dispose in the finally block.
Font font1 = new Font("Arial", 10.0f);
try
{
    byte charset = font1.GdiCharSet;
}
finally
{
    if (font1 != null)
    {
        ((IDisposable)font1).Dispose();
    }
}


// You can do the same thing with a using statement.
using (Font font2 = new Font("Arial", 10.0f))
{
    byte charset = font2.GdiCharSet;
}

عملگرهای && و ||

برای اجتناب از exceptionها و افزایش کارایی با درنظر نگرفتن مقایسه‌های غیرضروری، وقتی عمل مقایسه را انجام می‌دهید از && به جای & و || به جای | استفاده کنید، همان‌طور که در مثال زیر نشان داده شده است.

Console.Write("Enter a dividend: ");
var dividend = Convert.ToInt32(Console.ReadLine());

Console.Write("Enter a divisor: ");
var divisor = Convert.ToInt32(Console.ReadLine());

// If the divisor is 0, the second clause in the following condition
// causes a run-time error. The && operator short circuits when the
// first expression is false. That is, it does not evaluate the
// second expression. The & operator evaluates both, and causes 
// a run-time error when divisor is 0.
if ((divisor != 0) && (dividend / divisor > 0))
{
    Console.WriteLine("Quotient: {0}", dividend / divisor);
}
else
{
    Console.WriteLine("Attempted division by 0 ends up here.");
}

عملگر جدید

از شکل مختصر نمونه‌سازی اشیاء، توسط نوع ضمنی، استفاده کنید، همان‌طور که در اعلان زیر نشان داده شده است.

var instance1 = new ExampleClass();

خط قبلی معادل اعلان زیر است.

ExampleClass instance2 = new ExampleClass();

برای ساده‌سازی ایجاد شیء از مقداردهی اولیه شیء استفاده کنید.

// Object initializer.
var instance3 = new ExampleClass { Name = "Desktop", ID = 37414, 
    Location = "Redmond", Age = 2.3 };

// Default constructor and assignment statements.
var instance4 = new ExampleClass();
instance4.Name = "Desktop";
instance4.ID = 37414;
instance4.Location = "Redmond";
instance4.Age = 2.3;

مدیریت رویداد

اگر handler رویدادی را تعریف کنید که نیاز نباشد بعدا آن را حذف کنید، از عبارت لامبدا (lambda expression) استفاده کنید.

public Form2()
{
    // You can use a lambda expression to define an event handler.
    this.Click += (s, e) =>
        {
            MessageBox.Show(
                ((MouseEventArgs)e).Location.ToString());
        };
}
// Using a lambda expression shortens the following traditional definition.
public Form1()
{
    this.Click += new EventHandler(Form1_Click);
}

void Form1_Click(object sender, EventArgs e)
{
    MessageBox.Show(((MouseEventArgs)e).Location.ToString());
}

اعضای استاتیک

اعضای استاتیک را با استفاده از نام کلاس ClassName.StaticMember فراخوانی کنید. این عمل با استفاده از دسترسی استاتیک واضح، کد را خواناتر می‌سازد. تعریف یک عضو استاتیک در یک کلاس پایه با نام کلاس مشتق‌شده، خوب نیست. در حالی که کد کامپایل می‌شود، قابلیت خواندن کد گمراه‌کننده است و اگر یک عضو استاتیک را با نام مشابه‌ای به کلاس مشتق‌شده اضافه کنید ممکن است کد در آینده خراب شود.

کوئری‌های LINQ

از اسامی معنادار برای متغیرهای کوئری استفاده کنید. مثال زیر برای مشتریانی که در Seattle قرار دارند از seattleCustomers استفاده می‌کند.

var seattleCustomers = from cust in customers
                       where cust.City == "Seattle"
                       select cust.Name;

از نام مستعار برای اطمینان از اینکه نام‌های anonymous type با حروف درست نوشته شده‌اند استفاده کنید، با استفاده از Pascal casing.

var localDistributors =
    from customer in customers
    join distributor in distributors on customer.City equals distributor.City
    select new { Customer = customer, Distributor = distributor };

وقتی نام‌های ویژگی‌ها مبهم بودند، ویژگی‌ها را تغییر نام دهید. مثلا اگر کوئری شما نام مشتری و شناسه توزیع را برمی‌گرداند، به جای اینکه آن‌ها را به عنوان Name و ID استفاده کنید، آن‌ها را به مفاهیم روشن‌تری تغییر نام دهید، مثلا Name نام یک مشتری و ID شناسه یک توزیع‌کننده باشد.

var localDistributors2 =
    from cust in customers
    join dist in distributors on cust.City equals dist.City
    select new { CustomerName = cust.Name, DistributorID = dist.ID };

از نوع ضمنی در اعلان متغیرهای کوئری و متغیرهای محدوده دسترسی استفاده کنید.

var seattleCustomers = from cust in customers
                       where cust.City == "Seattle"
                       select cust.Name;

اجزای کوئری زیر بخش from را هم‌تراز کنید، همان‌طور که در مثال‌های قبلی نشان داده شده است.

از قسمت where قبل از بخش‌های دیگر کوئری استفاده کنید تا مطمئن شوید بخش‌های دیگر کوئری روی مجموعه داده‌های فیلتر شده عمل می‌کنند.

var seattleCustomers2 = from cust in customers
                        where cust.City == "Seattle"
                        orderby cust.Name
                        select cust;

برای دسترسی به مجموعه‌های درونی از from متعدد به جای بخش join استفاده کنید. مثلا در مجموعه‌ای از اشیای Student ممکن است هر کدام شامل مجموعه‌ای از نمرات امتحان باشند. وقتی کوئری زیر اجرا می‌شود هر نمره‌ای که بالای 90 است، همراه با نام خانوادگی دانشجویانی که نمره را دریافت کرده‌اند را برمی‌گرداند.

// Use a compound from to access the inner sequence within each element.
var scoreQuery = from student in students
                 from score in student.Scores
                 where score > 90
                 select new { Last = student.LastName, score };

آموزش سی شارپ