فصل ۵: مروری بر .NET، BCL و لایههای Application
فروش یا انتشار این ترجمه منوط به داشتن مجوز لازم از صاحب حقوق اثر است.
۵. مروری بر .NET
تصویر آغاز فصل ۵ در منبع.
تقریباً تمام قابلیتهای Runtime نسخهٔ .NET 8 از طریق مجموعهٔ بسیار بزرگی از Typeهای مدیریتشده (managed types) در دسترس قرار میگیرند. این Typeها در Namespaceهای سلسلهمراتبی سازماندهی شده و در مجموعهای از Assemblyها بستهبندی میشوند.
برخی از Typeهای .NET مستقیماً توسط CLR استفاده میشوند و برای محیط میزبانی مدیریتشده ضروریاند. این Typeها در Assemblyای با نام System.Private.CoreLib.dll قرار دارند (mscorlib.dll در .NET Framework) و شامل Typeهای داخلی C#، کلاسهای پایهٔ Collection و Typeهای مربوط به پردازش Stream، Serialization، Reflection، Threading و تعامل با کد Native هستند.
در سطحی بالاتر، Typeهای دیگری وجود دارند که قابلیتهای سطح CLR را «کاملتر» میکنند و امکاناتی مانند XML، JSON، Networking و Language-Integrated Query را فراهم میآورند. این مجموعه، Base Class Library یا BCL را تشکیل میدهد. بالاتر از آن نیز Application Layerها قرار دارند که APIهای لازم برای توسعهٔ انواع خاصی از Application، مانند Web یا Rich Client، را ارائه میکنند.
در این فصل موارد زیر را ارائه میکنیم:
- مروری بر BCL، که در ادامهٔ کتاب آن را پوشش میدهیم.
- خلاصهای سطحبالا از Application Layerها.
موارد جدید در .NET 7 و .NET 8
Base Class Libraryهای .NET 7 و .NET 8 شامل قابلیتهای جدید فراوان و بهبودهای متعدد در Performance هستند. بهطور مشخص:
- فرمت آرشیو Tar، که در سیستمهای Unix محبوب است، اکنون از طریق Typeهای موجود در Namespace جدید
System.Formats.Tar پشتیبانی میشود (بخش «Working with Tar Files» در صفحهٔ 722). کلاس ZipFile نیز بهبود یافته است تا بتوان Folderهای شامل File را مستقیماً درون یک Stream Zip کرد یا از یک Stream استخراج کرد.
- کلاس
Stream اکنون Methodهای ReadExactly و ReadAtLeast را در اختیار میگذارد تا خواندن از Streamها سادهتر شود (بخش «Reading and Writing» در صفحهٔ 697).
- اکنون کار با Permissionهای File در Unix پشتیبانی میشود (بخش «Unix file security» در صفحهٔ 727).
- پشتیبانی از
Span<T> و ReadOnlySpan<T> گسترش یافته است. بهطور خاص، Typeهای عددی و سایر Typeهای ساده اکنون از Formatting و Parsing با UTF-8 مستقیماً درون Span<byte> از طریق Interfaceهای جدید IUtf8SpanFormattable و IUtf8SpanParsable<TSelf> پشتیبانی میکنند؛ کلاس MemoryExtensions نیز Extension Methodهای بیشتری برای کمک به جستوجوی Valueها در Spanها دارد (بخش «Searching in Spans» در صفحهٔ 977).
- کلاس
Random اکنون Methodی به نام GetItems برای انتخاب Itemهای تصادفی از یک Collection و Methodی به نام Shuffle برای برهمزدن تصادفی ترتیب Itemها دارد (بخش «Random» در صفحهٔ 338).
- Typeهای تاریخ و زمان .NET اکنون Propertyهای
Microsecond و Nanosecond را در اختیار میگذارند.
- کلاس
JsonNode چند Method جدید از جمله GetValueKind، DeepEquals، DeepClone و ReplaceWith دارد (بخش «JsonNode» در صفحهٔ 575).
- دو Type جدید Read-only برای Collection وجود دارد:
FrozenDictionary<K,V> و FrozenSet<T>. این Typeها شبیه ImmutableDictionary<K,V> و ImmutableHashSet<T> موجود هستند، اما صرفاً برای خواندن بهینه شدهاند و Methodی برای Nondestructive Mutation ندارند (بخش «Frozen Collections» در صفحهٔ 410).
- RegEx اکنون از
RegexOptions.NonBacktracking پشتیبانی میکند تا به جلوگیری از حملات Denial-of-Service در Expressionهای ارائهشده توسط کاربر کمک کند (بخش «RegexOptions» در صفحهٔ 1013). Engine مربوط به Regular Expression نیز سریعتر شده است.
- Typeهای مربوط به Hashing با SHA-3، مشروط به پشتیبانی Operating System، اکنون در دسترساند (بخش «Hash Algorithms in .NET» در صفحهٔ 878).
Engine مربوط به JSON Serialization نیز با قابلیتهای جدید و Performance بهتر بهبود یافته است.
Runtime Targetها و TFMها
در File پروژه، Element با نام <TargetFramework> تعیین میکند پروژه برای کدام Runtime Build شود؛ این مقدار Framework Target یا Runtime Target نامیده میشود و با Target Framework Moniker یا TFM نمایش داده میشود. Valueهای معتبر شامل net8.0، net7.0، net6.0 و net5.0 (برای نسخههای 8، 7، 6 و 5 از .NET)، مقدار netcoreapp3.1 (برای .NET Core 3.1)، مقدار net48 (برای .NET Framework 4.8) و netstandard2.0 است که در بخش بعدی پوشش میدهیم. برای نمونه، هدفگذاری .NET 8 به این صورت است:
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<PropertyGroup>
میتوانید با استفاده از Element جمع <TargetFrameworks> چند Runtime را هدف قرار دهید. هر TFM با Semicolon از دیگری جدا میشود:
<TargetFrameworks>net8.0;net48</TargetFrameworks>
هنگامی که Multi-target میکنید، Compiler برای هر Target یک Output Assembly جداگانه تولید میکند.
Runtime Target از طریق Attribute با نام TargetFramework در Output Assembly Encode میشود. یک Assembly میتواند روی Runtimeای جدیدتر از Target خود اجرا شود، اما روی Runtime قدیمیتر نمیتواند.
.NET Standard
انبوه Libraryهای عمومی موجود در NuGet اگر فقط از .NET 8 پشتیبانی میکردند، ارزش امروزی خود را نداشتند. هنگام نوشتن یک Library معمولاً میخواهید مجموعهای از Platformها و نسخههای Runtime را پشتیبانی کنید. برای رسیدن به این هدف بدون ساخت Build جداگانه برای هر Runtime (Multi-targeting)، باید کمترین مخرج مشترک را هدف بگیرید. اگر فقط بخواهید از نسخههای مستقیم پیش از .NET 8 پشتیبانی کنید، این کار نسبتاً آسان است؛ برای مثال اگر پروژهٔ شما .NET 6 یعنی net6.0 را Target کند، Library شما روی .NET 6، .NET 7 و .NET 8 اجرا خواهد شد.
اگر بخواهید .NET Framework یا Runtimeهای قدیمی مانند Xamarin را نیز پشتیبانی کنید، وضعیت پیچیدهتر میشود. دلیل این است که هر یک از این Runtimeها CLR و BCLای با قابلیتهای همپوشان دارند و هیچ Runtimeای زیرمجموعهٔ کامل Runtime دیگری نیست.
.NET Standard با تعریف زیرمجموعههای مصنوعی که در طیف وسیعی از Runtimeها کار میکنند این مشکل را حل میکند. با Target کردن .NET Standard میتوانید بهسادگی Libraryهایی با دامنهٔ پشتیبانی گسترده بنویسید.
.NET Standard 2.0
کاربردیترین نسخه، .NET Standard 2.0 است. Libraryای که بهجای یک Runtime مشخص، .NET Standard 2.0 را Target کند بدون تغییر روی .NET مدرن (.NET 8/7/6/5 تا .NET Core 2) و .NET Framework 4.6.1 و بالاتر اجرا میشود. همچنین از UWP قدیمی (از 10.0.16299 به بعد) و Mono 5.4 و بالاتر، یعنی CLR/BCL مورد استفادهٔ نسخههای قدیمی Xamarin، پشتیبانی میکند.
برای Target کردن .NET Standard 2.0، موارد زیر را به File با پسوند .csproj اضافه کنید:
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PropertyGroup>
بیشتر APIهایی که در این کتاب شرح داده میشوند توسط .NET Standard 2.0 پشتیبانی میشوند؛ از میان مواردی که پشتیبانی نمیشوند نیز بیشترشان بهصورت Packageهای NuGet در دسترساند.
سایر .NET Standardها
.NET Standard 2.1 یک Superset از .NET Standard 2.0 است که فقط Platformهای زیر را پشتیبانی میکند:
.NET Standard 2.1 توسط هیچ نسخهای از .NET Framework پشتیبانی نمیشود و همین موضوع آن را بسیار کمکاربردتر از .NET Standard 2.0 میکند.
نسخههای قدیمیتر .NET Standard مانند 1.1، 1.2، 1.3 و 1.6 نیز وجود دارند که Compatibility آنها تا Runtimeهای بسیار قدیمی مانند .NET Core 1.0 یا .NET Framework 4.5 گسترش مییابد. Standardهای سری 1.x هزاران API موجود در 2.0 را ندارند، از جمله بخش زیادی از آنچه در این کتاب توضیح میدهیم، و در عمل منسوخ محسوب میشوند.
سازگاری .NET Framework و .NET 8
از آنجا که .NET Framework مدت بسیار زیادی وجود داشته است، برخورد با Libraryهایی که فقط برای .NET Framework موجودند و معادل .NET Standard، .NET Core یا .NET 8 ندارند غیرعادی نیست. برای کاهش این مشکل، پروژههای .NET 5+ و .NET Core مجازند به Assemblyهای .NET Framework Reference بدهند، با این شرطها:
- اگر Assembly مربوط به .NET Framework، API پشتیبانینشدهای را فراخوانی کند Exception رخ میدهد.
- Dependencyهای غیرساده ممکن است Resolve نشوند و در عمل اغلب نیز همین اتفاق میافتد.
در عمل، این روش بیشترین احتمال موفقیت را در Caseهای ساده دارد؛ برای نمونه Assemblyای که یک DLL مدیریتنشده را Wrap میکند.
Reference Assemblyها
هنگامی که .NET Standard را Target میکنید، پروژهٔ شما بهصورت ضمنی به Assemblyای با نام netstandard.dll Reference میدهد که تمام Typeها و Memberهای مجاز برای نسخهٔ انتخابی .NET Standard را در خود دارد. این Assembly را Reference Assembly مینامند، زیرا فقط برای استفادهٔ Compiler وجود دارد و هیچ کد Compileشدهای در آن نیست. در Runtime، Assemblyهای «واقعی» از طریق Attributeهای Assembly Redirection شناسایی میشوند؛ انتخاب Assemblyها به Runtime و Platformی بستگی دارد که Assembly نهایتاً روی آن اجرا میشود.
جالب این است که هنگام Target کردن .NET 8 نیز اتفاق مشابهی رخ میدهد. پروژه بهصورت ضمنی مجموعهای از Reference Assemblyها را Reference میکند که Typeهایشان آنچه را در Runtime Assemblyهای نسخهٔ انتخابشدهٔ .NET وجود دارد Mirror میکنند. این کار به Versioning و Cross-platform Compatibility کمک میکند و همچنین امکان میدهد نسخهای از .NET را Target کنید که با نسخهٔ نصبشده روی Machine شما متفاوت است.
نسخههای Runtime و زبان C#
بهصورت پیشفرض، Runtime Target پروژه تعیین میکند کدام نسخهٔ زبان C# استفاده شود:
| Runtime Target | نسخهٔ C# |
| .NET 8 | C# 12 |
| .NET 7 | C# 11 |
| .NET 6 | C# 10 |
| .NET 5 | C# 9 |
| .NET Core 3.x & 2.x | C# 8 |
| .NET Framework | C# 7.3 |
| .NET Standard 2.0 | C# 7.3 |
دلیل این است که نسخههای جدیدتر C# قابلیتهایی دارند که به Typeهایی متکیاند که در Runtimeهای جدیدتر معرفی شدهاند.
میتوانید نسخهٔ زبان را در File پروژه با Element با نام <LangVersion> Override کنید. استفاده از Runtime قدیمی، مانند .NET Framework، همراه با نسخهٔ جدیدتر زبان، مانند C# 12، به این معناست که قابلیتهای زبانی وابسته به Typeهای جدیدتر .NET کار نخواهند کرد؛ هرچند در برخی موارد میتوانید آن Typeها را خودتان تعریف کنید یا از Packageهای NuGet وارد کنید.
CLR و BCL
یادداشت برای Indexer: لطفاً همهٔ مطالب این بخش را، بهجز Heading سطح ۱، نادیده بگیرید. تمام مطالب این بخش در ادامهٔ کتاب با جزئیات بیشتر پوشش داده شدهاند.
Typeهای System
بنیادیترین Typeها مستقیماً در Namespace System قرار دارند. این Typeها شامل Typeهای Built-in زبان C#؛ Base Class با نام Exception؛ Base Classهای Enum، Array و Delegate؛ و نیز Nullable، Type، DateTime، TimeSpan و Guid هستند. Namespace System همچنین Typeهایی برای اجرای Functionهای ریاضی (Math)، تولید عدد تصادفی (Random) و Conversion بین Typeهای گوناگون (Convert و BitConverter) دارد.
فصل ۶ این Typeها و همچنین Interfaceهایی را توضیح میدهد که Protocolهای استاندارد مورد استفاده در سراسر .NET را برای کارهایی مانند Formatting (IFormattable) و Order Comparison (IComparable) تعریف میکنند.
Namespace System همچنین Interface با نام IDisposable و کلاس GC را برای تعامل با Garbage Collector تعریف میکند؛ این موضوع در فصل ۱۲ پوشش داده میشود.
پردازش Text
Namespace System.Text شامل کلاس StringBuilder، یعنی خویشاوند قابلویرایش یا Mutable نوع string، و Typeهای مربوط به Text Encoding مانند UTF-8 یعنی Encoding و Subtypeهای آن است. این موارد در فصل ۶ پوشش داده میشوند.
Namespace System.Text.RegularExpressions Typeهایی برای عملیات پیشرفتهٔ جستوجو و جایگزینی مبتنی بر Pattern دارد؛ این موضوع در فصل ۲۵ توضیح داده میشود.
Collectionها
.NET مجموعهای از کلاسها را برای مدیریت Collectionها ارائه میکند. این مجموعه شامل ساختارهای مبتنی بر List و Dictionary است؛ این Typeها همراه با مجموعهای از Interfaceهای استاندارد کار میکنند که ویژگیهای مشترک آنها را یکپارچه میکند. همهٔ Typeهای Collection در Namespaceهای زیر تعریف شدهاند که در فصل ۷ پوشش داده میشوند:
System.Collections // Nongeneric collections
System.Collections.Generic // Generic collections
System.Collections.Frozen // High-performance read-only collections
System.Collections.Immutable // General-purpose read-only collections
System.Collections.Specialized // Strongly typed collections
System.Collections.ObjectModel // Bases for your own collections
System.Collections.Concurrent // Thread-safe collection (Chapter 22)
Query کردن
Language-Integrated Query یا LINQ به شما امکان میدهد روی Collectionهای Local و Remote، برای مثال Tableهای SQL Server، Queryهای Type-safe اجرا کنید و در فصلهای ۸، ۹ و ۱۰ توضیح داده میشود. مزیت مهم LINQ این است که API یکدستی برای Query کردن در Domainهای گوناگون ارائه میکند. Typeهای اصلی در Namespaceهای زیر قرار دارند:
System.Linq // LINQ to Objects and PLINQ
System.Linq.Expressions // For building expressions manually
System.Xml.Linq // LINQ to XML
XML و JSON
XML و JSON بهطور گسترده در .NET پشتیبانی میشوند. فصل ۱۰ کاملاً بر LINQ to XML تمرکز دارد؛ یک XML Document Object Model یا DOM سبکوزن که میتوان آن را با LINQ ساخت و Query کرد. فصل ۱۱ کلاسهای کمسطح و پربازدهٔ Reader/Writer مربوط به XML، Schemaها و Stylesheetهای XML و Typeهای کار با JSON را پوشش میدهد:
System.Xml // XmlReader, XmlWriter
System.Xml.Linq // The LINQ to XML DOM
System.Xml.Schema // Support for XSD
System.Xml.Serialization // Declarative XML serialization for .NET types
System.Xml.XPath // XPath query language
System.Xml.Xsl // Stylesheet support
System.Text.Json // JSON reader/writer and DOM
System.Text.Json.Nodes // JsonNode API (DOM)
در Supplement آنلاین در نشانی متنی http://www.albahari.com/nutshell، JSON Serializer را پوشش میدهیم.
Diagnostics
در فصل ۱۳، Logging و Assertion را پوشش میدهیم و توضیح میدهیم چگونه با Processهای دیگر تعامل کنید، در Windows Event Log بنویسید و Performance Monitoring را مدیریت کنید. Typeهای مربوط به این موارد در System.Diagnostics و Namespaceهای زیرمجموعهٔ آن تعریف شدهاند.
Concurrency و Asynchrony
بسیاری از Applicationهای مدرن باید همزمان با رخدادن بیش از یک کار سروکار داشته باشند. از C# 5.0 به بعد، این موضوع با Functionهای Asynchronous و Constructهای سطحبالایی مانند Taskها و Task Combinatorها آسانتر شده است. فصل ۱۴، پس از آغاز با مبانی Multithreading، همهٔ این موارد را با جزئیات توضیح میدهد. Typeهای کار با Threadها و عملیات Asynchronous در Namespaceهای System.Threading و System.Threading.Tasks قرار دارند.
Streamها و Input/Output
.NET یک Model مبتنی بر Stream برای Input/Output یا I/O سطح پایین ارائه میکند. Streamها معمولاً برای خواندن و نوشتن مستقیم Fileها و Connectionهای Network استفاده میشوند و میتوان آنها را Chain کرد یا در Decorator Streamها Wrap کرد تا قابلیت Compression یا Encryption افزوده شود. فصل ۱۵ معماری Stream و همچنین پشتیبانی مشخص برای کار با File و Directory، Compression، Pipe و Memory-mapped File را توضیح میدهد. Typeهای Stream و I/O در System.IO و Namespaceهای زیرمجموعهٔ آن تعریف شدهاند.
Networking
بیشتر Protocolهای استاندارد Network مانند HTTP، TCP/IP و SMTP را میتوانید مستقیماً از طریق Typeهای موجود در System.Net استفاده کنید. در فصل ۱۶ نشان میدهیم چگونه با هر یک از این Protocolها ارتباط برقرار کنید؛ از کارهای ساده مانند Download از یک Web Page آغاز میکنیم و به استفادهٔ مستقیم از TCP/IP برای دریافت Email با POP3 میرسیم. Namespaceهای پوششدادهشده عبارتاند از:
System.Net
System.Net.Http // HttpClient
System.Net.Mail // For sending mail via SMTP
System.Net.Sockets // TCP, UDP, and IP
Assemblyها، Reflection و Attributeها
Assemblyهایی که Programهای C# به آنها Compile میشوند شامل Instructionهای اجرایی ذخیرهشده بهصورت IL و Metadata هستند؛ Metadata، Typeها، Memberها و Attributeهای Program را توصیف میکند. با Reflection میتوانید این Metadata را در Runtime بررسی کنید و کارهایی مانند فراخوانی Dynamic Methodها را انجام دهید. با Reflection.Emit نیز میتوانید در لحظه کد جدید بسازید.
در فصل ۱۷ ساختار Assemblyها و روش Load و Isolate کردن Dynamic آنها را توضیح میدهیم. در فصل ۱۸ Reflection و Attributeها را پوشش میدهیم و توضیح میدهیم چگونه Metadata را Inspect کنید، Functionها را Dynamic فراخوانی کنید، Attribute سفارشی بنویسید، Typeهای جدید Emit کنید و IL خام را Parse کنید. Typeهای مربوط به Reflection و Assembly در Namespaceهای زیر قرار دارند:
System
System.Reflection
System.Reflection.Emit
Dynamic Programming
در فصل ۱۹ برخی Patternهای Dynamic Programming و استفاده از Dynamic Language Runtime یا DLR را بررسی میکنیم. توضیح میدهیم چگونه Pattern بازدیدکننده یا Visitor را Implement کنید، Objectهای Dynamic سفارشی بنویسید و با IronPython تعامل داشته باشید. Typeهای Dynamic Programming در System.Dynamic قرار دارند.
Cryptography
.NET پشتیبانی گستردهای از Protocolهای رایج Hashing و Encryption ارائه میکند. در فصل ۲۰ Hashing، Encryption متقارن و Public-key و Windows Data Protection API را پوشش میدهیم. Typeهای مربوط در این Namespaceها تعریف شدهاند:
System.Security
System.Security.Cryptography
Threading پیشرفته
Functionهای Asynchronous در C#، Concurrent Programming را بهطور محسوسی سادهتر میکنند، زیرا نیاز به Techniqueهای سطح پایین را کاهش میدهند. با این حال هنوز موقعیتهایی وجود دارد که به Constructهای Signaling، Thread-local Storage، Reader/Writer Lock و موارد مشابه نیاز دارید.
فصل ۲۱ این موضوع را با جزئیات توضیح میدهد. Typeهای مربوط به Threading در Namespace System.Threading قرار دارند.
Parallel Programming
در فصل ۲۲ Libraryها و Typeهای استفاده از Processorهای چندهستهای را با جزئیات پوشش میدهیم؛ از جمله APIهای Task Parallelism، Data Parallelism دستوری و Parallelism تابعی یا PLINQ.
Span<T> و Memory<T>
برای کمک به Micro-optimization در نقاط حساس Performance، CLR مجموعهای از Typeها را فراهم میکند تا بتوانید به شیوهای Program بنویسید که بار روی Memory Manager کاهش یابد. دو Type کلیدی Span<T> و Memory<T> هستند که در فصل ۲۳ توضیح داده میشوند.
تعامل Native و COM
میتوانید هم با کد Native و هم با Component Object Model یا COM تعامل داشته باشید. Native Interoperability به شما اجازه میدهد Functionهای DLLهای مدیریتنشده را فراخوانی کنید، Callback ثبت کنید، Data Structureها را Map کنید و با Data Typeهای Native تعامل داشته باشید. COM Interoperability امکان فراخوانی COM Typeها روی Machineهای Windows و Expose کردن Typeهای .NET برای COM را فراهم میکند. Typeهای پشتیبان این Functionها در System.Runtime.InteropServices هستند و در فصل ۲۴ پوشش داده میشوند.
Regular Expressionها
در فصل ۲۵ توضیح میدهیم چگونه از Regular Expressionها برای Match کردن Patternهای Character در Stringها استفاده کنید.
Serialization
.NET چند System برای ذخیره و بازیابی Objectها در Representation باینری یا Text ارائه میکند. این Systemها هم برای Communication و هم برای ذخیره و بازیابی Objectها در File قابل استفادهاند. در Supplement آنلاین در نشانی متنی http://www.albahari.com/nutshell، هر چهار Serialization Engine یعنی Binary Serializer، JSON Serializer جدیداً بهروزشده، XML Serializer و Data Contract Serializer را پوشش میدهیم.
Compiler Roslyn
خود Compiler زبان C# با C# نوشته شده است؛ این Project «Roslyn» نام دارد و Libraryهای آن بهصورت Packageهای NuGet در دسترساند. با این Libraryها میتوانید Functionality Compiler را به شیوههای بسیاری فراتر از Compile کردن Source Code به Assembly به کار ببرید، برای مثال برای نوشتن ابزارهای تحلیل Code و Refactoring. Roslyn در Supplement آنلاین در نشانی متنی http://www.albahari.com/nutshell پوشش داده میشود.
Application Layerها
Applicationهای مبتنی بر User Interface یا UI را میتوان به دو گروه تقسیم کرد: Thin Client که عملاً یک Website است، و Rich Client که Programی است که End User باید آن را Download کرده و روی Computer یا Mobile Device نصب کند.
برای نوشتن Thin-client Application در C#، ASP.NET Core وجود دارد که روی Windows، Linux و macOS اجرا میشود. ASP.NET Core همچنین برای نوشتن Web API طراحی شده است.
برای Rich-client Application، چند API در دسترس است:
- لایهٔ Windows Desktop شامل APIهای محبوب WPF و Windows Forms است و روی Desktopهای Windows 7/8/10/11 اجرا میشود.
- WinUI 3 یا Windows App SDK جانشین UWP است و فقط روی Desktopهای Windows 10+ اجرا میشود.
- UWP امکان نوشتن Windows Store Appهایی را فراهم میکند که روی Desktop Windows 10+ و Deviceهایی مانند Xbox یا HoloLens اجرا میشوند.
- MAUI، که پیشتر Xamarin نام داشت، روی Deviceهای Mobile با iOS و Android اجرا میشود. MAUI همچنین اجازه میدهد Desktop Applicationهای Cross-platform برای macOS از طریق Catalyst و Windows از طریق Windows App SDK نوشته شوند.
Libraryهای UI شخص ثالث و Cross-platform مانند Avalonia نیز وجود دارند. برخلاف MAUI، Avalonia روی Linux هم اجرا میشود و برای Platformهای Desktop به لایهٔ واسط Catalyst/WinUI متکی نیست، که Development و Debugging را سادهتر میکند.
ASP.NET Core
ASP.NET Core جانشینی سبکوزن و Modular برای ASP.NET است و برای ساخت Website، Web APIهای مبتنی بر REST و Microserviceها مناسب است. همچنین میتواند همراه با دو Framework محبوب Single-page Application یعنی React و Angular اجرا شود.
ASP.NET از Pattern محبوب Model-View-Controller یا MVC و همچنین Technology جدیدتری به نام Blazor پشتیبانی میکند که در آن Client-side Code بهجای JavaScript با C# نوشته میشود.
ASP.NET Core روی Windows، Linux و macOS اجرا میشود و میتواند در یک Process سفارشی Self-host شود. برخلاف سلف آن در .NET Framework یعنی ASP.NET، به System.Web و بار تاریخی Web Forms وابسته نیست.
مانند هر Architecture از نوع Thin Client، ASP.NET Core در مقایسه با Rich Clientها مزیتهای عمومی زیر را دارد:
- در سمت Client هیچ Deploymentی لازم نیست.
- Client میتواند روی هر Platformی که Web Browser داشته باشد اجرا شود.
- Updateها بهآسانی Deploy میشوند.
Windows Desktop
Application Layer مربوط به Windows Desktop برای نوشتن Rich-client Application دو API مربوط به UI ارائه میکند: WPF و Windows Forms. هر دو API روی Windows Desktop/Server از نسخهٔ 7 تا 11 اجرا میشوند.
WPF
WPF در سال 2006 معرفی شد و از آن زمان پیوسته توسعه یافته است. برخلاف سلف خود Windows Forms، WPF Controlها را بهطور صریح با DirectX Render میکند و مزیتهای زیر را دارد:
- از Graphicهای پیشرفته مانند Transformationهای دلخواه، Rendering سهبعدی، Multimedia و Transparency واقعی پشتیبانی میکند. Skinning از طریق Style و Template پشتیبانی میشود.
- واحد اصلی اندازهگیری آن مبتنی بر Pixel نیست؛ بنابراین Applicationها در هر DPI بهدرستی نمایش داده میشوند.
- پشتیبانی گسترده و انعطافپذیری از Layout دارد؛ بنابراین میتوانید Application را Localize کنید بدون اینکه Elementها روی یکدیگر بیفتند.
- استفاده از DirectX باعث میشود Rendering سریع باشد و بتواند از Hardware Acceleration گرافیکی استفاده کند.
- Data Binding قابلاعتمادی ارائه میکند.
- UIها را میتوان بهصورت Declarative در Fileهای XAML توصیف کرد که مستقل از Fileهای «code-behind» قابل نگهداریاند؛ این کار به جداسازی Appearance از Functionality کمک میکند.
یادگیری WPF بهدلیل اندازه و پیچیدگی آن زمانبر است. Typeهای نوشتن WPF Application در Namespace System.Windows و همهٔ Subnamespaceهای آن، بهجز System.Windows.Forms، قرار دارند.
Windows Forms
Windows Forms یک API برای Rich Client است که همراه اولین نسخهٔ .NET Framework در سال 2000 ارائه شد. در مقایسه با WPF، Windows Forms Technology نسبتاً سادهای است که بیشتر قابلیتهای لازم برای نوشتن یک Windows Application معمولی را فراهم میکند. برای نگهداری Legacy Applicationها نیز همچنان اهمیت زیادی دارد. اما در مقایسه با WPF، ایرادهای متعددی دارد که بیشترشان از این واقعیت ناشی میشود که Wrapperای روی GDI+ و Win32 Control Library است:
- هرچند Windows Forms مکانیزمهایی برای DPI-awareness دارد، همچنان بسیار آسان است Applicationی نوشته شود که روی Clientهایی با DPI متفاوت از Machine توسعهدهنده خراب نمایش داده شود.
- API رسم Controlهای غیراستاندارد GDI+ است که با وجود انعطافپذیری نسبتاً مناسب، در Render کردن Areaهای بزرگ کند است و بدون Double Buffering ممکن است Flicker کند.
- Controlها Transparency واقعی ندارند.
- بیشتر Controlها Noncompositional هستند. برای مثال نمیتوانید Image Control را داخل Header یک Tab Control قرار دهید. سفارشیسازی List View، Combo Box و Tab Control به روشی که در WPF بدیهی است، در Windows Forms زمانبر و دشوار است.
- Implement کردن Dynamic Layout بهشکل درست و قابلاعتماد دشوار است.
نکتهٔ آخر دلیل بسیار خوبی برای ترجیح WPF به Windows Forms است، حتی اگر Business Application شما صرفاً به UI نیاز داشته باشد و نه یک «User Experience». Elementهای Layout در WPF مانند Grid، کنار هم قرار دادن Label و Text Box را طوری آسان میکنند که همیشه همتراز بمانند، حتی بعد از Localization با تغییر زبان، بدون Logic پیچیده و بدون Flicker. همچنین مجبور نیستید خود را به کمترین مخرج مشترک Screen Resolution محدود کنید؛ Elementهای Layout در WPF از ابتدا برای سازگاری صحیح با Resize طراحی شدهاند.
در سمت مثبت، Windows Forms نسبتاً ساده است و هنوز تعداد خوبی Control شخص ثالث برای آن وجود دارد.
Typeهای Windows Forms در Namespaceهای System.Windows.Forms در System.Windows.Forms.dll و System.Drawing در System.Drawing.dll قرار دارند. مورد دوم Typeهای GDI+ برای رسم Controlهای سفارشی را نیز شامل میشود.
UWP و WinUI 3
UWP یک API مربوط به Rich Client برای نوشتن UIهای Touch-first است که Desktop و Deviceهای Windows 10+ را Target میکنند. واژهٔ «Universal» به توانایی اجرای آن روی طیفی از Deviceهای Windows 10 شامل Xbox، Surface Hub، HoloLens و در زمان خود Windows Phone اشاره دارد.
API مربوط به UWP از XAML استفاده میکند و تا حدی شبیه WPF است. تفاوتهای اصلی آن عبارتاند از:
- روش اصلی Distribution برای UWP Appها Windows Store است.
- UWP Appها برای کاهش خطر Malware در Sandbox اجرا میشوند؛ یعنی نمیتوانند کارهایی مانند خواندن یا نوشتن Fileهای دلخواه را انجام دهند و نمیتوانند با Administrative Elevation اجرا شوند.
- UWP به WinRT Typeهایی متکی است که بخشی از Operating System یعنی Windows هستند، نه Managed Runtime. در نتیجه هنگام نوشتن App باید محدودهای از نسخههای Windows را مشخص کنید، برای مثال Windows 10 build 17763 تا Windows 10 build 18362. یعنی یا باید API قدیمی را Target کنید یا از Customerها بخواهید آخرین Windows Update را نصب کنند.
بهدلیل محدودیتهای ناشی از این تفاوتها، UWP هرگز به محبوبیت WPF و Windows Forms نرسید. برای رفع این مسئله، Microsoft، UWP را به Technology جدیدی با نام Windows App SDK تبدیل کرده است که UI Layer آن WinUI 3 نام دارد.
Windows App SDK، APIهای WinRT را از Operating System به Runtime منتقل میکند؛ در نتیجه Interfaceای کاملاً مدیریتشده Expose میشود و نیاز به Target کردن Range مشخصی از نسخهٔ Operating System از بین میرود. علاوه بر این:
- با APIهای Windows Desktop یعنی Windows Forms و WPF بهتر Integrate میشود.
- اجازه میدهد Applicationهایی بنویسید که خارج از Sandbox مربوط به Windows Store اجرا شوند.
- روی آخرین .NET اجرا میشود، بهجای آنکه مانند UWP به .NET Core 2.2 گره خورده باشد.
با وجود این بهبودها، WinUI 3 هنوز به محبوبیت گستردهٔ APIهای کلاسیک Windows Desktop نرسیده است. Windows App SDK نیز در زمان نگارش از Xbox یا HoloLens پشتیبانی نمیکند و به Download جداگانه توسط End User نیاز دارد.
MAUI
MAUI که پیشتر Xamarin نام داشت به شما اجازه میدهد Mobile Appهایی با C# توسعه دهید که iOS و Android را Target میکنند؛ همچنین Desktop Appهای Cross-platform که macOS را از طریق Catalyst و Windows را از طریق Windows App SDK Target میکنند.
CLR/BCLای که روی iOS و Android اجرا میشود Mono نام دارد و مشتقی از Runtime متنباز Mono است. از نظر تاریخی، Mono کاملاً با .NET Compatible نبود و Libraryهایی که هم روی Mono و هم روی .NET اجرا میشدند .NET Standard را Target میکردند. اما از .NET 6، Interface عمومی Mono با .NET ادغام شد و در عمل Mono به یک Implementation از .NET تبدیل شد.
MAUI شامل Interface یکپارچهٔ Project، Hot Reloading و پشتیبانی از Blazor Desktop و Hybrid App است. برای اطلاعات بیشتر، نشانی منبع بهصورت متن: https://github.com/dotnet/maui.
[این صفحه در فایل اصلی خالی است.]