لكل نوع في .NET اسم كامل مكوّن من فضاء أسماء واسم النوع: System.Console وSystem.Collections.Generic.List<T> وSystem.Text.StringBuilder. تجمع فضاءات الأسماء الأنواع المترابطة وتمنع تعارض الأسماء، فيتعايش صنفك Order أو Timer مع أصناف تحمل الاسم نفسه من المكتبات. وتستورد الموجّهة using في أعلى الملف فضاء أسماء كي تستخدم الأسماء القصيرة.
المخرجات:
Cart: tea, honey
1
لا تؤثر الموجّهة using إلا في الأسماء وقت الترجمة. لا تحمّل مكتبة ولا تضيف شيفرة إلى البرنامج؛ أما المكتبات المتاحة فتحددها مراجع المشروع وحزم NuGet. إن أبلغ المترجم أن نوعًا أو فضاء أسماء "could not be found (are you missing a using directive or an assembly reference?)"، وهو الخطأ CS0246، فإما أن سطر using مفقود أو أن الحزمة غير مُشار إليها.
التصريح بفضاءات أسمائك
ضع الأنواع داخل كتلة namespace. يمكن تداخل فضاءات الأسماء وكتابتها بالنقاط، ويمكن توزيع فضاء الأسماء نفسه على ملفات كثيرة.
المخرجات:
120.00 via DHL
Shop.Billing.Invoice
namespace Shop.Billing { } اختصار لـ namespace Shop { namespace Billing { } }. تستطيع الشيفرة داخل Shop الإشارة إلى Billing.Invoice دون البادئة Shop.، لأن الأسماء يُبحث عنها أولًا في فضاءات الأسماء المحيطة.
الأعراف: ابدأ باسم الشركة أو المنتج (Contoso.Payments)، ثم الميزة أو الطبقة، وطابق بنية المجلدات (Contoso.Payments/Refunds/RefundService.cs يحتوي Contoso.Payments.Refunds). لا تسمِّ صنفًا باسم فضاء أسمائه أبدًا (Shop.Shop)، فهذا يفرض تأهيلًا مربكًا في كل مكان.
الأسماء المستعارة
تمنح using Name = Namespace.Type; نوعًا (أو فضاء أسماء) اسمًا محليًا. حالتان تستدعيانها: تقصير نوع عام طويل، وحل تعارض.
المخرجات:
latte: 3.60
order 17
لا تنطبق الأسماء المستعارة إلا على الملف الذي صُرّح بها فيه (ما لم تكن global، كما سيأتي). في C# 12 وما بعده يمكن للاسم المستعار أن يسمّي أي نوع، بما في ذلك الصفوف والمصفوفات: using Point = (int X, int Y);.
المراجع الملتبسة (CS0104)
حين يحتوي فضاءا أسماء مستوردان على نوع بالاسم نفسه يكون استخدام الاسم القصير خطأ. الحالة التقليدية هي Timer، الموجود في System.Threading وSystem.Timers و(في تطبيقات سطح المكتب) System.Windows.Forms:
using System.Threading;
using System.Timers;
var t = new Timer(1000);
// error CS0104: 'Timer' is an ambiguous reference between
// 'System.Timers.Timer' and 'System.Threading.Timer'
ثلاثة حلول، من الأكثر محلية إلى الأقل: اكتب الاسم المؤهّل كاملًا (new System.Timers.Timer(1000))، أو أضف اسمًا مستعارًا يحدّد أيهما تقصد، أو احذف الموجّهة التي لا تحتاجها.
المخرجات:
250
System.Timers.Timer
System.Threading.Timer
إن عرّف فضاء أسمائك نوعًا اسمه System أو Console، فإن البادئة global:: تفرض البحث من الجذر: global::System.Console.WriteLine("hi");. تستخدمها الشيفرة المولَّدة في كل مكان لهذا السبب.
using static
تستورد using static الأعضاء الساكنة لنوع واحد، فتُستدعى دون اسم النوع. تناسب الشيفرة التي تستدعي الصنف نفسه مرارًا، مثل Math:
المخرجات:
Area: 28.27
Hypotenuse: 5
42
تعمل using static أيضًا مع التعدادات (using static System.DayOfWeek; تتيح لك كتابة Monday) ومع أصنافك الساكنة. استخدمها حيث تبقى الأسماء القصيرة غير ملتبسة؛ فـ WriteLine وحدها في ملف كبير قد تترك القارئ يتساءل أي كاتب هو.
global using وفضاءات الأسماء على مستوى الملف (C# 10)
ميزتان من C# 10 تقلّصان التكرار في أعلى الملفات. تنطبق global using على كل ملف في المشروع، وتُحفظ عادة في ملف واحد مثل GlobalUsings.cs:
// GlobalUsings.cs, C# 10 and later
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using Money = System.Decimal;
تستطيع مشاريع SDK في .NET 6 وما بعده توليدها عنك. مع <ImplicitUsings>enable</ImplicitUsings> في ملف .csproj (الافتراضي في القوالب الجديدة) يحصل مشروع الكونسول على System وSystem.Collections.Generic وSystem.IO وSystem.Linq وSystem.Net.Http وSystem.Threading وSystem.Threading.Tasks؛ وتحصل مشاريع الويب على فضاءات أسماء ASP.NET Core أيضًا. لهذا تبدأ ملفات Program.cs الحديثة بالشيفرة مباشرة.
ويصرّح فضاء الأسماء على مستوى الملف بفضاء الأسماء للملف كله بفاصلة منقوطة بدل كتلة، فيوفّر مستوى واحدًا من الإزاحة:
// C# 10 and later
namespace Shop.Billing;
public class Invoice
{
public decimal Amount { get; set; }
}
لا يمكن أن يحتوي الملف إلا على فضاء أسماء واحد على مستوى الملف، ولا يمكن خلطه بفضاءات أسماء الكتل في الملف نفسه. تستخدم المشاريع الأقدم وسكربتات Unity والشيفرة التي تستهدف .NET Framework شكل الكتلة المعروض سابقًا.
أين توضع موجّهات using، والعبارة using
يجب أن تأتي موجّهات using قبل أي تصريح بفضاء أسماء أو نوع في الملف (وglobal usings قبل كل شيء آخر). ويمكن أيضًا وضعها داخل كتلة فضاء أسماء، فتنطبق هناك فقط؛ تختلف أدلة الأسلوب في ذلك، ومعظم شيفرة .NET تبقيها في أعلى الملف.
للكلمة using مهمة ثانية لا علاقة لها بالأولى داخل الدوال: العبارة using using (var file = File.OpenRead(path)) { ... } تستدعي Dispose على الكائن حين تنتهي الكتلة، فتغلق الملفات والاتصالات. تشترك معها في الكلمة ولا شيء غير ذلك. راجع صفحة العبارة using.
الأسئلة الشائعة
ماذا تفعل using في C#؟
في أعلى الملف، using System.Text; موجّهة تستورد فضاء أسماء، فتكتب StringBuilder بدل System.Text.StringBuilder. لا تضيف شيفرة ولا تحمّل شيئًا؛ إنما تقصّر الأسماء فقط. أما داخل دالة فإن using (var f = ...) ميزة مختلفة، هي العبارة using، التي تتخلّص من كائن في نهاية الكتلة.
ما هو فضاء الأسماء في C#؟
فضاء الأسماء (namespace) مجموعة مسمّاة من الأنواع تمنع تعارض الأسماء وتنظّم الشيفرة، مثل System.Collections.Generic أو MyShop.Billing. يمكن لصنفين أن يحملا الاسم نفسه إن كانا في فضاءي أسماء مختلفين. عُرفًا تتبع فضاءات الأسماء بنية المجلدات وتبدأ باسم الشركة أو المنتج.
ما هي using static في C#؟
تستورد using static System.Math; الأعضاء الساكنة لنوع واحد، فتستدعي Sqrt(16) وتقرأ PI دون البادئة Math.. تعمل مع أي صنف، بما في ذلك أصنافك والتعدادات. استخدمها حيث تبقى الأسماء القصيرة واضحة، كالشيفرة كثيرة الرياضيات.
كيف أصلح الخطأ "is an ambiguous reference" في C#؟
يعني الخطأ CS0104 أن فضاءي أسماء مستوردين يحتويان كلاهما على نوع بهذا الاسم، مثل Timer في System.Threading وSystem.Timers. اكتب الاسم المؤهّل كاملًا (System.Timers.Timer)، أو احذف إحدى موجّهتي using، أو أضف اسمًا مستعارًا: using Timer = System.Timers.Timer;.
ما هي global using في C#؟
تستورد global using System.Text; (C# 10) فضاء أسماء لكل ملف في المشروع، لا للملف الذي تظهر فيه فقط. تولّد مشاريع SDK في .NET 6 وما بعده مجموعة من global usings تلقائيًا حين يُضبط <ImplicitUsings>enable</ImplicitUsings>، ولهذا لا تحتوي ملفات Program.cs الجديدة على أسطر using.