فصل ۱: معرفی C# و .NET — شیءگرایی، ایمنی نوع و Runtimeها
فروش یا انتشار این ترجمه منوط به داشتن مجوز لازم از صاحب حقوق اثر است.
۱. معرفی C# و .NET
C# یک زبان برنامهنویسی همهمنظوره، نوعامن (type-safe) و شیءگرا (object-oriented) است. هدف این زبان، بهرهوری برنامهنویس است. برای رسیدن به این هدف، C# میان سادگی، قدرت بیان و کارایی تعادل برقرار میکند. معمار اصلی این زبان از نخستین نسخهٔ آن، آندرس هایلسبرگ (Anders Hejlsberg، سازندهٔ Turbo Pascal و معمار Delphi) بوده است.
زبان C# نسبت به پلتفرم خنثی است و با مجموعهای از زمانهای اجرای مخصوص پلتفرمهای مختلف کار میکند.
شیءگرایی (Object Orientation)
C# پیادهسازی غنیای از پارادایم شیءگرایی است که کپسولهسازی (encapsulation)، وراثت (inheritance) و چندریختی (polymorphism) را دربر میگیرد. کپسولهسازی یعنی ایجاد یک مرز پیرامون یک شیء، بهمنظور جداکردن رفتار بیرونی (عمومی) آن از جزئیات پیادهسازی درونی (خصوصی) آن. از دیدگاه شیءگرایی، ویژگیهای متمایز C# عبارتاند از:
سیستم نوع یکپارچه
واحد سازندهٔ بنیادی در C#، واحدی کپسولهشده از داده و توابع است که «نوع» (type) نام دارد. C# دارای یک سیستم نوع یکپارچه است که در آن همهٔ نوعها در نهایت یک نوع پایهٔ مشترک دارند. این یعنی همهٔ نوعها، چه اشیای کسبوکار را نمایش دهند و چه نوعهای ابتدایی مانند اعداد باشند، قابلیتهای پایهٔ یکسانی را به اشتراک میگذارند. برای مثال، یک نمونه از هر نوعی را میتوان با فراخوانی متد ToString آن به رشته تبدیل کرد.
کلاسها و اینترفیسها
در پارادایم سنتی شیءگرایی، تنها نوع موجود «کلاس» است. در C# چندین نوع دیگر نیز وجود دارد که یکی از آنها اینترفیس (interface) است. اینترفیس شبیه کلاسی است که نمیتواند داده نگه دارد. بنابراین فقط میتواند رفتار را تعریف کند (و نه حالت را)؛ قابلیتی که هم وراثت چندگانه و هم جداسازی مشخصات از پیادهسازی را امکانپذیر میکند.
ویژگیها، متدها و رویدادها
در پارادایم کاملاً شیءگرا، همهٔ توابع متد هستند. در C#، متدها فقط یکی از انواع اعضای تابعیاند؛ اعضای تابعی همچنین شامل ویژگیها (properties) و رویدادها (events) میشوند (و انواع دیگری نیز وجود دارد). ویژگیها اعضای تابعیای هستند که بخشی از حالت یک شیء، مانند رنگ یک دکمه یا متن یک برچسب، را کپسوله میکنند. رویدادها اعضای تابعیای هستند که واکنشنشاندادن به تغییرات حالت یک شیء را ساده میکنند.
با اینکه C# در درجهٔ اول یک زبان شیءگرا است، از پارادایم برنامهنویسی تابعی نیز، بهطور مشخص در موارد زیر، ایده میگیرد:
توابع را میتوان مانند مقدارها در نظر گرفت
C# با استفاده از delegateها اجازه میدهد توابع بهصورت مقدار، به توابع دیگر فرستاده شوند یا از آنها بازگردند.
C# از الگوهای خلوص پشتیبانی میکند
هستهٔ برنامهنویسی تابعی، پرهیز از استفاده از متغیرهایی است که مقدارشان تغییر میکند و استفاده از الگوهای اعلانی بهجای آنهاست. C# قابلیتهای کلیدیای برای کمک به این الگوها دارد؛ از جمله توانایی نوشتن فوری توابع بینام که متغیرها را «capture» میکنند (عبارتهای لامبدا)، و توانایی انجام برنامهنویسی فهرستی یا واکنشی از طریق عبارتهای پرسوجو. C# همچنین recordها را فراهم میکند که نوشتن نوعهای تغییرناپذیر (فقطخواندنی) را آسان میکنند.
ایمنی نوع (Type Safety)
C# در درجهٔ اول زبانی نوعامن است؛ یعنی نمونههای نوعها فقط از طریق قراردادهایی که تعریف میکنند میتوانند با یکدیگر تعامل داشته باشند و بدین ترتیب سازگاری درونی هر نوع حفظ میشود. برای نمونه، C# اجازه نمیدهد با یک نوع رشتهای طوری تعامل کنید که گویی یک نوع عدد صحیح است.
بهطور دقیقتر، C# از نوعدهی ایستا (static typing) پشتیبانی میکند؛ یعنی زبان، ایمنی نوع را در زمان کامپایل اعمال میکند. این علاوه بر ایمنی نوعی است که در زمان اجرا نیز اعمال میشود.
نوعدهی ایستا دستهٔ بزرگی از خطاها را پیش از آنکه برنامه حتی اجرا شود حذف میکند. این رویکرد، بار بررسی اینکه همهٔ نوعهای یک برنامه بهدرستی با یکدیگر جور هستند را از تستهای واحد زمان اجرا به کامپایلر منتقل میکند. در نتیجه مدیریت برنامههای بزرگ بسیار آسانتر شده و رفتار آنها قابلپیشبینیتر و مقاومتر میشود. افزون بر این، نوعدهی ایستا به ابزارهایی مانند IntelliSense در Visual Studio امکان میدهد در نوشتن برنامه به شما کمک کنند، زیرا برای هر متغیر میدانند نوع آن چیست و در نتیجه چه متدهایی را میتوان روی آن فراخوانی کرد. چنین ابزارهایی همچنین میتوانند همهٔ جاهایی را که یک متغیر، نوع یا متد در برنامه استفاده شده است شناسایی کنند و refactoring قابلاعتماد را ممکن سازند.
C# را همچنین یک زبان «قویاً نوعدهیشده» (strongly typed) مینامند، زیرا قواعد نوع آن بهطور سختگیرانه اعمال میشوند (چه بهصورت ایستا و چه در زمان اجرا). برای نمونه، نمیتوانید تابعی را که برای پذیرش عدد صحیح طراحی شده است با یک عدد ممیز شناور فراخوانی کنید، مگر اینکه ابتدا آن عدد ممیز شناور را صریحاً به عدد صحیح تبدیل کنید. این کار به جلوگیری از اشتباهها کمک میکند.
مدیریت حافظه (Memory Management)
C# برای انجام مدیریت خودکار حافظه به زمان اجرا متکی است. زمان اجرای زبان مشترک (Common Language Runtime) یک زبالهروب (garbage collector) دارد که بهعنوان بخشی از برنامهٔ شما اجرا میشود و حافظهٔ اشیایی را که دیگر هیچ ارجاعی به آنها وجود ندارد بازیابی میکند. این کار برنامهنویسان را از آزادسازی صریح حافظهٔ یک شیء بینیاز میسازد و مشکل اشارهگرهای نادرست را که در زبانهایی مانند C++ دیده میشود از میان میبرد.
C# اشارهگرها را حذف نمیکند؛ فقط آنها را برای بیشتر کارهای برنامهنویسی غیرضروری میسازد. در نقاط حساس از نظر کارایی و برای تعاملپذیری، استفاده از اشارهگرها و تخصیص صریح حافظه در بلوکهایی که با unsafe علامتگذاری شدهاند مجاز است.
C# زمانهای اجرایی دارد که از پلتفرمهای زیر پشتیبانی میکنند:
- Windows 7+ Desktop (برای برنامههای rich-client، وب، سرور و خط فرمان)
- macOS (برای برنامههای وب و خط فرمان — و برنامههای rich-client از طریق Mac Catalyst)
- Linux (برای برنامههای وب و خط فرمان)
- Android و iOS (برای برنامههای موبایل)
- دستگاههای Windows 10 (Xbox، Surface Hub و HoloLens) از طریق UWP
همچنین فناوریای به نام Blazor وجود دارد که میتواند C# را به WebAssembly کامپایل کند تا در مرورگر اجرا شود.
CLRها، BCLها و زمانهای اجرا (CLRs, BCLs, and Runtimes)
پشتیبانی زمان اجرا برای برنامههای C# از یک زمان اجرای زبان مشترک (Common Language Runtime) و یک کتابخانهٔ کلاس پایه (Base Class Library) تشکیل میشود. یک زمان اجرا همچنین میتواند یک لایهٔ کاربردی سطحبالاتر را دربر بگیرد که شامل کتابخانههایی برای توسعهٔ برنامههای rich-client، موبایل یا وب است (شکل ۱-۱ را ببینید). زمانهای اجرای متفاوتی وجود دارند تا امکان ساخت انواع متفاوت برنامهها و نیز پشتیبانی از پلتفرمهای مختلف فراهم شود.
شکل ۱-۱. معماری زمان اجرا
زمان اجرای زبان مشترک (Common Language Runtime)
یک زمان اجرای زبان مشترک (CLR) خدمات ضروری زمان اجرا، مانند مدیریت خودکار حافظه و مدیریت استثناها را فراهم میکند. (واژهٔ «common» به این واقعیت اشاره دارد که همان زمان اجرا را میتوان با زبانهای برنامهنویسی مدیریتشدهٔ دیگری مانند F#، Visual Basic و Managed C++ به اشتراک گذاشت.)
C# یک زبان مدیریتشده (managed language) نامیده میشود، زیرا کد منبع را به کد مدیریتشده کامپایل میکند که با زبان میانی (Intermediate Language یا IL) نمایش داده میشود. CLR، IL را به کد بومی ماشین مانند X64 یا X86 تبدیل میکند؛ معمولاً درست پیش از اجرا. این فرایند کامپایل Just-In-Time (JIT) نامیده میشود. کامپایل پیشاززمان (ahead-of-time) نیز برای بهبود زمان راهاندازی در اسمبلیهای بزرگ یا دستگاههای دارای منابع محدود در دسترس است (و هنگام توسعهٔ برنامههای موبایل برای رعایت قواعد فروشگاه برنامهٔ iOS نیز کاربرد دارد).
ظرف کد مدیریتشده «assembly» نام دارد. یک assembly نهتنها IL، بلکه اطلاعات نوع (metadata) را نیز در خود دارد. وجود metadata به assemblyها اجازه میدهد بدون نیاز به فایلهای اضافی، به نوعهای موجود در assemblyهای دیگر ارجاع دهند.
یک برنامه میتواند metadata خودش را پرسوجو کند (reflection) و حتی در زمان اجرا IL جدید تولید کند (reflection.emit).
کتابخانهٔ کلاس پایه (Base Class Library)
یک CLR همیشه همراه با مجموعهای از assemblyها عرضه میشود که کتابخانهٔ کلاس پایه (BCL) نام دارند. BCL قابلیتهای اصلی مورد نیاز برنامهنویسان را فراهم میکند؛ مانند مجموعهها، ورودی/خروجی، پردازش متن، کار با XML/JSON، شبکه، رمزنگاری، تعاملپذیری، همروندی و برنامهنویسی موازی.
BCL همچنین نوعهایی را پیادهسازی میکند که خود زبان C# به آنها نیاز دارد (برای قابلیتهایی مانند پیمایش، پرسوجو و ناهمگامی) و به شما اجازه میدهد بهطور صریح به قابلیتهای CLR، مانند Reflection و مدیریت حافظه، دسترسی داشته باشید.
زمانهای اجرا (Runtimes)
یک زمان اجرا (که framework نیز نامیده میشود) یک واحد قابل استقرار است که آن را دانلود و نصب میکنید. زمان اجرا از یک CLR (همراه BCL آن) بهاضافهٔ یک لایهٔ کاربردی اختیاری و متناسب با نوع برنامهای که مینویسید — وب، موبایل، rich client و غیره — تشکیل میشود. (اگر یک برنامهٔ کنسولی خط فرمان یا یک کتابخانهٔ بدون رابط کاربری مینویسید، به لایهٔ کاربردی نیازی ندارید.)
هنگام نوشتن یک برنامه، یک زمان اجرای مشخص را هدف میگیرید؛ یعنی برنامهٔ شما از قابلیتهایی که آن زمان اجرا فراهم میکند استفاده میکند و به آنها وابسته است. انتخاب زمان اجرا همچنین تعیین میکند برنامهٔ شما از چه پلتفرمهایی پشتیبانی خواهد کرد.
جدول زیر گزینههای اصلی زمان اجرا را فهرست میکند:
| لایهٔ کاربردی | CLR/BCL | نوع برنامه | اجرا روی... |
| ASP.NET | .NET 8 | وب | Windows، Linux، macOS |
| Windows Desktop | .NET 8 | Windows | Windows 10+ |
| WinUI 3 | .NET 8 | Windows | Windows 10+ |
| MAUI | .NET 8 | موبایل، دسکتاپ | iOS، Android، macOS، Windows 10+ |
| .NET Framework | .NET Framework | وب، Windows | Windows 7+ |
شکل ۱-۲ این اطلاعات را بهصورت گرافیکی نمایش میدهد و همچنین راهنمایی برای مطالبی است که در کتاب پوشش داده میشود.
شکل ۱-۲. زمانهای اجرای C#
.NET 8
.NET 8 زمان اجرای متنباز پرچمدار مایکروسافت است. میتوانید برنامههای وب و کنسولی بنویسید که روی Windows، Linux و macOS اجرا شوند؛ برنامههای rich-client که روی Windows 10+ و macOS اجرا شوند؛ و برنامههای موبایل که روی iOS و Android اجرا شوند. تمرکز این کتاب بر CLR و BCL در .NET 8 است.
برخلاف .NET Framework، .NET 8 از پیش روی دستگاههای Windows نصب نیست. اگر تلاش کنید برنامهای برای .NET 8 را بدون وجود زمان اجرای صحیح اجرا کنید، پیامی ظاهر میشود و شما را به صفحهای وب هدایت میکند که میتوانید زمان اجرا را از آن دانلود کنید. میتوانید با ساخت یک استقرار self-contained که بخشهای مورد نیاز برنامه از زمان اجرا را همراه خود دارد، از این وضعیت جلوگیری کنید.
Windows Desktop و WinUI 3
برای نوشتن برنامههای rich-client که روی Windows 10 و نسخههای بالاتر اجرا میشوند، میتوانید میان APIهای کلاسیک Windows Desktop (Windows Forms و WPF) و WinUI 3 انتخاب کنید. APIهای Windows Desktop بخشی از زمان اجرای .NET Desktop هستند، در حالی که WinUI 3 بخشی از Windows App SDK است (که جداگانه دانلود میشود).
APIهای کلاسیک Windows Desktop از سال 2006 وجود داشتهاند و از پشتیبانی بسیار خوب کتابخانههای شخص ثالث برخوردارند؛ همچنین تعداد فراوانی پرسش پاسخدادهشده در سایتهایی مانند StackOverflow دربارهٔ آنها وجود دارد. WinUI 3 در سال 2022 منتشر شد و برای نوشتن برنامههای مدرن و فراگیر که از جدیدترین کنترلهای Windows 10+ استفاده میکنند در نظر گرفته شده است. WinUI 3 جانشین Universal Windows Platform (UWP) است.
MAUI
MAUI (Multi-platform App UI) در درجهٔ اول برای ساخت برنامههای موبایل iOS و Android طراحی شده است، هرچند میتوان از آن برای برنامههای دسکتاپی که از طریق Mac Catalyst و WinUI 3 روی macOS و Windows اجرا میشوند نیز استفاده کرد. MAUI تکاملیافتهٔ Xamarin است و به یک پروژه اجازه میدهد چند پلتفرم را هدف بگیرد.
.NET Framework
.NET Framework زمان اجرای اصلی و فقط-Windows مایکروسافت برای نوشتن برنامههای وب و rich-client است که فقط روی دسکتاپ/سرور Windows اجرا میشوند. انتشار عمدهٔ جدیدی برای آن برنامهریزی نشده است، اگرچه مایکروسافت بهدلیل تعداد بسیار زیاد برنامههای موجود، همچنان نسخهٔ فعلی 4.8 را پشتیبانی و نگهداری خواهد کرد.
در .NET Framework، CLR/BCL با لایهٔ کاربردی یکپارچه است. برنامههایی که با .NET Framework نوشته شدهاند را میتوان برای .NET 8 دوباره کامپایل کرد، هرچند معمولاً به مقداری تغییر نیاز دارند. برخی قابلیتهای .NET Framework در .NET 8 وجود ندارند (و برعکس).
.NET Framework بهصورت پیشفرض همراه Windows نصب است و بهطور خودکار از طریق Windows Update وصله میشود. هنگامی که .NET Framework 4.8 را هدف میگیرید، میتوانید از قابلیتهای C# 7.3 و نسخههای پیش از آن استفاده کنید. (میتوانید با مشخصکردن نسخهٔ زبانی جدیدتر در فایل پروژه این محدودیت را override کنید؛ این کار همهٔ تازهترین قابلیتهای زبان را فعال میکند، بهجز قابلیتهایی که به پشتیبانی یک زمان اجرای جدیدتر نیاز دارند.)
زمانهای اجرای خاص (Niche Runtimes)
زمانهای اجرای خاص زیر نیز وجود دارند:
- Unity یک پلتفرم توسعهٔ بازی است که اجازه میدهد منطق بازی با C# اسکریپتنویسی شود.
- Universal Windows Platform (UWP) برای نوشتن برنامههای touch-first طراحی شده بود که روی دسکتاپ و دستگاههای Windows 10+، از جمله Xbox، Surface Hub و HoloLens، اجرا میشوند. برنامههای UWP در sandbox اجرا میشوند و از طریق Windows Store عرضه میشوند. UWP از نسخهای از CLR/BCL مربوط به .NET Core 2.2 استفاده میکند و بعید است این وابستگی بهروزرسانی شود؛ در عوض، مایکروسافت توصیه کرده است کاربران به جایگزین مدرن آن، WinUI 3، مهاجرت کنند. اما چون WinUI 3 فقط از دسکتاپ Windows پشتیبانی میکند، UWP همچنان برای هدفگرفتن Xbox، Surface Hub و HoloLens کاربرد خاص خود را دارد.
- .NET Micro Framework برای اجرای کد .NET روی دستگاههای تعبیهشده با منابع بسیار محدود (کمتر از یک مگابایت) است.
اجرای کد مدیریتشده درون SQL Server نیز ممکن است. با یکپارچهسازی SQL Server CLR، میتوانید توابع سفارشی، stored procedureها و aggregationها را با C# بنویسید و سپس آنها را از SQL فراخوانی کنید. این قابلیت همراه با .NET Framework و یک CLR ویژهٔ «hosted» کار میکند که برای محافظت از یکپارچگی فرایند SQL Server، یک sandbox اعمال میکند.
تاریخچهای کوتاه از C# (A Brief History of C#)
در ادامه، برای خوانندگانی که از قبل با نسخهای قدیمیتر از این زبان آشنا هستند، گاهشمار معکوسی از قابلیتهای جدید هر نسخهٔ C# ارائه میشود.
چه چیزهایی در C# 12 جدید است
C# 12 همراه Visual Studio 2022 عرضه میشود و هنگامی به کار میرود که .NET 8 را هدف بگیرید.