مقدمه

ساختارهای تکرار در زبان‌های برنامه‌نویسی به ما امکان می‌دهند که مجموعه‌ای از دستورات را تا رسیدن به یک شرط مشخص، تکرار کنیم. در C# چهار حلقه‌ی while، do...while، for و foreach به این منظور معرفی شده‌اند. در این درس، این حلقه‌های تکرار را بررسی می‌کنیم و کاربرد هر یک از آنها را خواهیم دید. البته حلقه‌ی foreach روی کالکشن‌ها کار می‌کند و بنابراین، بررسی آن را به فصل بعد و بعد از آشنایی با کالکشن‌ها موکول می‌کنیم.

ساخت یک پروژه

قبل از هر چیز، یک پروژه با استفاده از dotnet CLI ایجاد می‌کنیم. قبلاً دیدیم که با استفاده از کامند dotnet new می‌توانیم یک پروژه‌ی .NET را بر اساس تمپلت‌های از قبل نوشته شده، ایجاد کنیم. این کامند دارای فرم کلی زیر است.

$ dotnet new <Template> [Options]

که در آن:

  • <Template> نوع پروژه را مشخص می‌کند که می‌تواند console یا classlib یا mvc و غیره باشد.
  • [Options] مشخص‌کننده‌ی آپشن‌های اختیاری است که به کانفیگ پروژه مربوط هستند. برای مثال، آپشن -n یا --name برای تعیین نام پروژه و آپشن -o یا --output برای تعیین محل ذخیره‌ی پروژه کاربرد دارند. آپشن --framework هم همانطور که قبلاً دیدیم، برای تعیین فریمورک هدف کاربرد دارد.

اگر از این کامند بدون هیچ آپشنی استفاده کنیم، نام پروژه از روی دایرکتوری جاری گرفته می‌شود، پروژه در دایرکتوری جاری ذخیره می‌شود و آخرین ورژنی از .NET که روی سیتم نصب است، به عنوان فریمورک هدف تعیین می‌شود. پس، اگر برای مثال، در یک دایرکتوری با نام Test قرار داشته باشیم، دو کامند زیر، معادل هستند.

$ dotnet new console 
$ dotnet new console -n Test -o . 
          

آپشن -o به یک مسیر (path) نیاز دارد و همانطور که می‌دانید، در مسیرها کاراکتر نقطه به دایرکتوری جاری اشاره می‌کند.

یک دایرکتوری با نام CsharpLoops در مکان دلخواهتان ایجاد کنید و سپس، vscode را جرا کنید و از طریق منوی File > Open Folder... این دایرکتوری را در vscode باز کنید. در پنل Terminal کامند زیر را اجرا کنید.

$ dotnet new console

به این ترتیب، یک پروژه با نام CsharpLoops ایجاد می‌شود و فایل‌های مورد نیاز به دایرکتوری پروژه اضافه می‌شوند.

حلقه‌های while و do...while

حلقه‌ی while شرطی را بررسی می‌کند و اگر این شرط برقرار باشد، دستورات بدنه‌ی خود را اجرا می‌کند. وقتی شرط حلقه برقرار نباشد، حلقه‌ی while متوقف می‌شود. ساختار کلی حلقه‌ی while به صورت زیر است.

while (condition) 
  {
    // loop body 
  }

تا زمانی که عبارت بولین condition برابر با true باشد، دستورات بدنه‌ی حلقه اجرا می‌شوند. بنابراین، کد بدنه‌ی حلقه باید به گونه‌ای باشد که شرط حلقه با هر تکرار، تغییر کند. در غیر این صورت، یک حلقه‌ی بی‌پایان خواهیم داشت که هیچ‌وقت متوقف نمی‌شود. در مثال زیر، گزاره‌ی counter++; در انتهای حلقه، متضمن پایان‌پذیری حلقه است.

Copy Icon Program.cs
int counter = 0; 

while (counter < 6) 
{
  Console.WriteLine(counter);
  counter++;
}

اگر این کد را با استفاده از کامند dotnet run اجرا کنیم، خواهیم دید که اعداد صفر تا 5 در خروجی نمایش داده می‌شوند. وقتی متغیر counter به مقدار 6 می‌رسد، شرط حلقه دیگر برقرار نیست و بنابراین، حلقه متوقف می‌شود.

دیدیم که حلقه‌ی while اول شرط را بررسی می‌کند و در صورت برقراری شرط، دستورات حلقه را اجرا می‌کند. بنابراین، این امکان وجود دارد که در همان اولین بررسی، شرط حلقه برقرار نباشد و نتیجتاً دستورات حلقه یک بار هم اجرا نشوند. اما حلقه‌ی do...while ابتدا دستورات حلقه را اجرا می‌کند و سپس، شرط حلقه را برای تکرار بعدی بررسی می‌کند. بنابراین، دستورات یک حلقه‌ی do...while لااقل یک بار اجرا می‌شوند. ساختار کلی یک حلقه‌ی do...while به صورت زیر است.

do 
{
  // loop body 
} while (condition)

در کد زیر، اعداد صفر تا 5 را این بار با استفاده از یک حلقه‌ی do...while چاپ کرده‌ایم.

Copy Icon Program.cs
int counter = 0;

do
{
  Console.WriteLine(counter);
  counter++;
} while (counter < 6);

حالا به مثال زیر دقت کنید که کمی پیچیده‌تر است.

Copy Icon Program.cs
void WhileLoopExample()
{
  string userIsDone = "";
  while (userIsDone.ToLower() != "yes")
  {
    Console.WriteLine("In while loop");
    Console.Write("Are you done? [yes] [no]: ");
    userIsDone = Console.ReadLine();
  }
}
            
WhileLoopExample();

در اینجا متدی به نام WhileLoopExample() تعریف و فراخوانی شده است. کاری که این متد انجام می‌دهد این است که تا زمانی که کاربر عبارتی غیر از yes را وارد کند، متن In While loop را چاپ می‌کند. در مورد این متد، چند نکته‌ی قابل ذکر وجود دارد.

  • کلمه کلیدی void در امضای متد، به این معناست که این متد دارای خروجی یا مقدار بازگشتی نیست.
  • برای شرط حلقه، قبل از مقایسه، مقدار متغیر userIsDone با استفاده از متدی به نام ToLower() به یک رشته با حروف کوچک تبدیل شده تا اگر احیاناً کاربر مقداری مثل Yes یا YES را وارد کرد، حلقه متوقف شود.
  • در گزاره‌ی دوم از بدنه‌ی حلقه، از متد Write() استفاده شده که مثل WriteLine() عمل می‌کند با این تفاوت که به خط بعدی منتقل نمی‌شود.
  • متد ReadLine() از کلاس Console برای دریافت ورودی از کاربر به کار می‌رود. وقتی برنامه به این خط برسد، منتظر ورود متن توسط کاربر می‌ماند و خطی را که کاربر وارد می‌کند، در متغیر userIsDone قرار می‌دهد.

حلقه for

حلقه‌ی for پر کاربردترین ساختار تکرار در C# است. این حلقه معمولاً زمانی استفاده می‌شود که بخواهیم مجموعه‌ای از دستورات را برای تعداد دفعات مشخصی اجرا کنیم. ساختار کلی حلقه‌ی for به صورت زیر است.

for (counter; condition; iterator) 
{
  // loop body
}

همانطور که می‌بینید، ابتدا کلمه کلیدی for و سپس یک جفت پرانتز ایجاد شده و درون پرانتزها سه آیتم داریم که با سمی‌کالن از هم جدا شده‌اند. آیتم اول معمولاً (اما نه همیشه) متغیری است که روی یک مقدار عددی تنظیم شده و شمارنده‌ی تعداد دفعات اجرای حلقه محسوب می‌شود. به همین دلیل آن را counter نامیده‌ایم. آیتم دوم یعنی condition یک عبارت شرطی است که تعیین کننده‌ی زمان توقف حلقه است. در واقع، حلقه تا زمانی ادامه پیدا می‌کند که این شرط برقرار باشد. آیتم سوم نیز iterator یا تکرارگر نامیده شده و با هر بار اجرای حلقه مقدار متغیر شمارنده را افزایش یا کاهش می‌دهد تا بعد از هر بار اجرای حلقه یک گام به نقطه‌ی پایان حلقه نزدیک شویم. در پایان نیز یک جفت آکلاد قرار دارد که دستوراتی را که در هر تکرار حلقه باید انجام شوند، شامل است.

در کد زیر، از حلقه‌ی for برای چاپ اعداد صفر تا 5 استفاده شده است.

Copy Icon Program.cs
for (int i = 0; i < 6; i++)
{
  Console.WriteLine(i);
}

حلقه‌های تودرتو

با قرار دادن یک حلقه درون یک حلقه‌ی دیگر، می‌توانیم یک حلقه‌ی تودرتو (nested loop) ایجاد کنیم. اجازه دهید کاربرد حلقه‌های تودرتو شده را با استفاده از یک مثال ببینیم. در یک صفحه‌ی شطرنج، سطرها با استفاده از اعداد 1 تا 8 و ستون‌ها با استفاده از حروف a تا h نامگذاری می‌شوند و به این ترتیب، هر خانه از صفحه نامی مثل ix پیدا می‌کند که در ان i عدد مربوط به سطر و x حرف مربوط به ستون است. قصد داریم برنامه‌ای بنویسیم که نام همه‌ی خانه‌های صفحه ی شطرنج را چاپ کند.

Copy Icon Program.cs
for (int row = 1; row <= 8; row++)
{
  for (char column = 'a'; column <= 'h'; column++)
  {
    Console.WriteLine($"The cell is {row}{column}");
  }
}

برنامه را اجرا کنید و نتیجه‌ی آن را ببینید. به ازای هر مقداری که متغیر حلقه‌ی بیرونی می‌گیرد، دستور موجود در حلقه‌ی درونی به ازای مقدار a تا h برای متغیر حلقه‌ی درونی، اجرا می‌شود.