استایل جدید برنامههای C#
در ورژنهای 9 و 10 زبان C# چند ویژگی جدید برای سادهسازی و مختصرنویسی کدها معرفی شد. سه مورد از
مهمترین این
ویژگیها که در درس مفاهیم اسمبلی و فضای نام در
.NET هم از آنها نام بردیم، عبارتند از:
-
ویژگی Top-level statements که باعث میشود Entry point برنامه به صورت ضمنی توسط کامپایلر ایجاد شود و
بنابراین، متد Main() در برنامه وجود نداشته باشد.
-
ویژگی Implicit using directives که بسته به نوع پروژه، تعدادی عبارت using را به طور
ضمنی به پروژه اضافه
میکند.
-
ویژگی Global using directives که به ما امکان میدهد عبارات using را در سطح پروژه (و نه
فایل) تعریف کنیم.
ویژگی Top-level statements
در نسخههای قبل از C# 9 نقطهی ورود یا Entry point برنامههای اجرایی C# یک متد با نام Main() بود که باید حتماً
در پروژه ایجاد میشد و کدهایی که باید در نهایت اجرا میشدند، درون این متد نوشته میشد. اما با معرفی ویژگی
Top-level statements در C# 9 این امکان فراهم شد تا Entry point برنامه به صورت ضمنی توسط کامپایلر ایجاد شود و
نیازی به تعریف متد Main() نباشد. کد زیر مثالی است که در درس قبلی با استفاده از
استایل قدیمی، یعنی بدون استفاده
از Top-level statements نوشتیم.
Program.cs
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
اما با تکیه بر ویژگی Top-level statements میتوانیم این کد را به صورت زیر خلاصه کنیم.
Program.cs
using System;
Console.WriteLine("Hello, World!")
همانطور که میبینید، دیگر نیازی به تعریف یک کلاس مثل Program و متد Main() و نوشتن کدها درون آن نیست. ما
گزارههای (statements) اجرایی را بیرون از هر کلاس و متدی مینویسیم و این گزارههای Top-level توسط کامپایلر
به یک متد که به صورت ضمنی ایجاد شده و ما حتی نامش را هم نمیدانیم (و نیازی هم به آن نداریم) منتقل شده و این
متد به عنوان Entry point برنامه در نظر گرفته میشود.
ما میتوانیم از این ویژگی استفاده کنیم یا نکنیم و الزامی در این مورد وجود ندارد. اگر به نوشتن کدهای اجرایی
درون متد Main() عادت دارید، میتوانید از همان استایل قدیمی استفاده کنید.
ویژگی Implicit using directives
در C# 10 یک ویژگی با نام Implicit using directive معرفی شد که به طور ضمنی چند عبارت using پرکاربرد را به
پروژه اضافه میکند تا نیازی به وارد کردن آنها به صورت دستی نباشد. اینکه کدام عبارات using به پروژه اضافه
شوند، به نوع پروژه بستگی دارد. مثلاٍ در پروژههای کنسول، عبارات using زیر به صورت ضمنی
به پروژه اضافه
میشوند.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
در نسخههای اخیر C# این ویژگی به صورت پیشفرض فعال است و بنابراین، میتوانیم در مثال قبل، گزارهی
using system;
را از بالای فایل حذف کنیم.
Program.cs
Console.WriteLine("Hello, World!");
اگر بخواهیم این ویژگی را غیرفعال کنیم، باید در فایل پروژه، عبارت enable زیر را به disable تبدیل کنیم.
SimpleCsharpApp.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
ویژگی Global using directives
ویژگی دیگری که در C# 10 معرفی شد، ویزگی Global using directives است که به ما امکان میدهد با اضافه کردن کلمه
کلیدی global به ابتدای یک عبارت using ترتیبی دهیم که آن فضای نام
برای کل پروژه در دسترس باشد. برای مثال، اگر
عبارات زیر را در یکی از فایلهای پروژه وارد کنیم، این دو فضای نام برای سایر فایلهای پروژه هم در دسترس
خواهند بود.
Program.cs
global using System;
global using System.Collections.Generic;
آناتومی یک اپلیکیشن C#
در فصل قبل، دیدیم که چطور میتوانیم از Visual Studio و Visual Studio Code برای ساخت اپهای
.NET استفاده کنیم. مایکروسافت به جز این دو IDE یک گزینهی دیگر را هم برای توسعهی
اپهای .NET به ما پیشنهاد میدهد و آن GitHub Codespaces است که در واقع، ورژن تحت وب vscode است.
علاوه بر این ابزارهای مایکروسافتی، گزینههای دیگری مثل JetBrains Rider هم قابل انتخاب هستند.
برای ادامهی این دوره، ما از vscode استفاده میکنیم که روی پلتفرمهای ویندوز، مک و لینوکس
قابل استفاه است و رایگان و متنباز هم هست.
قصد داریم یک اپلیکیشن ساده ایجاد کرده و با بررسی بخشهای مختلف آن، اطلاعاتی در مورد کلیات اپلیکیشنهای
C# به
دست آوریم. پس vscode را اجرا کنید و از منوی File گزینهی Open Folder را انتخاب کنید و سپس در کادری که باز
میشود، به محل دلخواهتان بروید و یک دایرکتوری با نام SimpleCsharpApp ایجاد
کنید. سپس، این دایرکتوری را
انتخاب کرده و روی گزینهی Select Folder کلیک کنید تا در محیط vscode
باز شود. البته که این دایرکتوری فعلاً
خالی است اما میتوانید در پنل سمت چپ ببینید که این دایرکتوری در vscode باز شده است. حالا اگر از منوی View
گزینهی Terminal را انتخاب کنید، پنل ترمینال در vscode باز شده و
میتوانید ببینید که دایرکتوری جاری، همین
دایرکتوری SimpleCsharpApp است. این موضوع را میتوانید با استفاده از کامند pwd هم تست کنید.
بعد از اینکه مطمئن شدید که دایرکتوری جاری در ترمینال، دایرکتوری SimpleCsharpApp است، کامند زیر را اجرا کنید.
$ dotnet new console --framework net8.0
از فصل قبل یادآوری میکنم که این کامند باعث ایجاد یک پروژهی همنام با دایرکتوری جاری میشود. البته این بار
آپشن --use-program-main را به کار نبردهایم تا پروژه با تکیه بر قابلیت Top-level
statements و نتیجتاً بدون
کلاس Program و متد Main() ایجاد شود.
به این ترتیب، یک دایرکتوری به نام obj (که فعلاً کاری به محتویاتش نداریم) به
همراه یک فایل همنام با پروژه و
دارای پسوند .csproj (که فایل پروژه نامیده میشود) و یک فایل کد با نام Program.cs در دایرکتوری پروژه ایجاد
میشود. وقتی روی فایل Program.cs کلیک کنید، محتویاتش نمایش داده میشود و در
ضمن، یک فایل دیگر که دارای پسوند
.sln است (و فایل سولوشن نامیده میشود) و یک دایرکتوری دیگر با نام bin به دایرکتوری پروژه اضافه میشوند.
محتویات فایل Program.cs را پاک کنید و کد زیر را در آن وارد کنید.
Program.cs
int x = 12 * 30;
Console.WriteLine(x);
این برنامهی ساده از دو گزاره (statement) تشکیل شده است. گزارهی اول حاصلضرب 12 و 30 را در یک متغیر از نوع
int با نام x ذخیره میکند و گزارهی دوم، مقدار این متغیر را با
استفاده از یک متد با نام WriteLine() که روی
کلاسی به نام Console تعریف شده، در خروجی چاپ میکند. پس، اجرای این برنامه منجر به نمایش
مقدار 360 میشود.
برنامهی بالا با همهی سادگی و اختصار، اجزایی دارد که در اینجا یک معرفی کوتاه از آنها ارائه میدهیم:
-
نوع int: در فصل اول گفتیم که نوعهای درونی .NET در استانداردی به نام CTS
تعریف شدهاند و زبانهای .NET
از نامهای مستعاری برای ارجاع به این نوعها استفاده میکنند. در C# کلمه کلیدی int نام مستعاری است که برای
ارجاع به نوع System.Int32 تعریف شده است. میتوان به جای int از نام
اصلی این نوع هم استفاده کرد که البته
خیلی کار عاقلانهای نیست.
- متغیر x: تعریف متغیرها در C# باید با اعلان نوع آنها همراه باشد.
البته میتوان به جای اعلان صریح نوع
متغیر از کلمه کلیدی var هم استفاده کرد که در این مورد بعداً توضیحات لازم داده خواهد
شد. در مثال بالا،
متغیر x دارای نوع int و در نتیجه یک عدد صحیح 32 بیتی است.
-
عملگر *: نماد * نشاندهدهی عملگر ضرب است که یکی از عملگرهای حسابی (arithmetic operators) در C#
است.
عملگرهای حسابی و سایر انواع عملگرها را در آینده معرفی میکنیم.
-
کلاس Console: در فصل اول گفتیم که کلاس (class) یکی از نوعهای پنجگانهی
C# است که واحد اصلی برنامهنویسی
شیگرا هم محسوب میشود. یک کلاس، اعضایی مانند متدها و پراپرتیهای مرتبط با هم را گروه میکند. کلاس Console
شامل اعضایی است که به اعمال I/O مربوط هستند.
-
متد WriteLine(): یکی از اعضای کلاس Console که در سادهترین
حالت، مقداری را که به عنوان آرگومان دریافت
کرده، در خروجی چاپ میکند.
باز هم از فصل اول یادآوری میکنم که نوعهایی مانند کلاسها و اینترفیسها در فضاهای نام (namespaces) تعریف
شدهاند و هر نوعی به یک فضای نام تعلق دارد. کلاس Console هم متعلق به فضای نام System است که به خاطر فعال
بودن ویژگی Implicit using directives به طور ضمنی به پروژه اضافه شده و به همین دلیل است که ما میتوانیم بدون
اینکه از System نام ببریم، از کلاس Console استفاده کنیم. اگر ویژگی
مذکور را غیرفعال کنیم و یا از نسخههای
قبل از C# 10 استفاده کنیم، باید یا یک گزارهی using System; به بالای فایل اضافه کنیم
و یا اینکه کلاس Console
را به شکل System.Console مورد دسترسی قرار دهیم.
بهبود برنامه با تعریف یک متد
یک متد (method) مجموعهای از گزارههاست که نامی به آن اختصاص داده شده تا هر وقت لازم باشد، اجرا شود. فرض
کنید میخواهیم برنامهای داشته باشیم که یک عدد را بر حسب فوت دریافت کرده و معادل آن را به اینچ برگرداند (هر
فوت برابر با 12 اینچ است).
Program.cs
Console.WriteLine(FeetToInches(30));
Console.WriteLine(FeetToInches(100));
int FeetToInches(int feet)
{
int inches = feet * 12;
return inches;
}
بهترین کار این است که متدی تعریف کنیم که کار تبدیل فوت به اینچ را برای هر عدد ورودی انجام میدهد. در کد بالا
یک متد با نام FeetToInches() تعریف شده که یک پارامتر از نوع int
دارد که feet نامیده شده است. کله کلیدی int
در ابتدای تعریف متد بالا به این معناست که نوع بازگشتی متد باید از نوع int باشد. در
بدنهی متد هم مقدار ورودی
متد در 12 ضرب شده و حاصل این ضرب با استفاده از کلمه کلیدی return برگردانده شده است. به
این ترتیب، ما متدی
داریم که کار تبدیل فوت به اینچ را برایمان انجام میدهد. از این متد دو بار برای مقادیر 30 و 100 فوت استفاده
کردهایم.