آليات تنسيق السلاسل النصية في C#/.NET كثيرة ومتنوعة: من الدمج البسيط للكائنات، مرورًا بالاستدعاءات إلى الطريقة object.ToString() المتجاوزة، وصولًا إلى استخدام ICustomFormatter (وهو غير مشمول في هذا التمرين).
أكثر آليتين شيوعًا لتنسيق السلاسل النصية هما إقحام السلاسل النصية وString.Format(). ويمكن أيضًا استخدام الصنف StringBuilder (cross-ref-tba) لبناء سلسلة نصية عند وجود تعقيد مثل تعدد الأسطر.
ToString()
تحتوي System.Object()، التي ترث منها جميع الأصناف والبنيات، على طريقة ToString(). على سبيل المثال، ستُنتج new DateTime(2019, 5, 23).ToString() النص "05/23/2019 00:00:00" (على مؤشر ترابط بثقافة الولايات المتحدة، انظر أدناه). وهناك حالات مثل دمج السلاسل النصية يُستدعى فيها هذا ToString() الافتراضي ضمنيًا، فعبارة "" + new DateTime(2019, 5, 23) تعطي النتيجة نفسها.
وإضافة إلى الطريقة الافتراضية ToString()، تمتلك الأنواع التي يشكّل تنسيقها مشكلةً تحميلات زائدة تقبل سلسلة تنسيق أو حتى موفر تنسيق. ومن أبرز هذه الأنواع في BCL (مكتبة الفئات الأساسية) الأعداد والتواريخ والتعدادات ومعرّفات GUID.
تأخذ String.Format() سلسلة نصية (يُشار إليها في التوثيق باسم التنسيق المركب) تتألف من نص ثابت وعناصر نائبة (تُعرف في التوثيق باسم عناصر التنسيق) وعددًا متغيرًا من الوسائط. وتُحل قيمة الإرجاع كل عنصر تنسيق باستخدام الوسيط المقابل له، ثم تدمج القيم المحلولة مع النص الثابت.
string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5, new DateTime(2010, 2, 25))
// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
قد يكون Format() خيارًا أفضل من الإقحام عندما يُستخدم التنسيق في تعبيرات متعددة كنوع من القوالب، أو عندما يكون تضمين التنسيق مع التعبيرات المطلوب تنسيقها مرهقًا للغاية، كما في حالة [السلاسل النصية الحرفية][verbatim-strings].
تُعرف هذه الآلية تقنيًا باسم التنسيق المركب.
وتجد في هذا المقال قائمة أوفى بالطرق المنتِجة للسلاسل النصية التي تستفيد من التنسيق المركب.
تبدأ السلاسل النصية المُقحمة بالرمز $ وتضم تعبيرات تُقيَّم وقت التشغيل محصورة بين قوسين معقوفين. وبنية عنصر التنسيق هي: $"{<interpolationExpression>[,<alignment>][:<formatString>]}". وهي تغني عن وجود قائمة وسائط منفصلة. والنتيجة مكافئة وظيفيًا لآلية String.Format().
ويمكن أن يتضمن التعبير أي شيء داخل النطاق. و_المحاذاة_ هي طول "الحقل" الذي يستقر فيه النص. فإذا كانت المحاذاة موجبة حُشِي النص بمسافات على اليسار، وإذا كانت سالبة كان الحشو على يمين النص.
var loadsOf = 55.5;
var thatDay = new DateTime(2010, 2, 25);
$"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password."
// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
يُعرف النص الواقع بين قوسين معقوفين، سواء كان عنصرًا نائبًا في حالة التنسيق المركب أو تعبيرًا مُقحمًا في حالة إقحام السلاسل النصية، باسم عنصر تنسيق.
ويمكن أن يتألف عنصر التنسيق من 3 أجزاء على الأكثر. الجزء الأول هو التعبير الإلزامي أو العنصر النائب للوسيط كما في مثال الكود أعلاه. وإضافة إلى ذلك، توجد محاذاة اختيارية (تُقدَّم بفاصلة، ",") و_سلسلة تنسيق_ اختيارية (تُقدَّم بنقطتين رأسيتين، ":").
{<interpolationExpression>[,<alignment>][:<formatString>]}
وتحدد المحاذاة طول "الحقل" الذي يوضع فيه النص، مع حشوه بالمسافات من اليسار إذا كانت المحاذاة موجبة أو من اليمين إذا كانت سالبة.
وتحدد سلسلة التنسيق شكل النص الناتج، مثل ما إذا كان ينبغي تضمين فواصل الآلاف في عدد، أو ما إذا كان ينبغي إخراج جزء التاريخ فقط من كائن DateTime.
يوضح الكود التالي عرض جزء التاريخ من كائن DateTime وعدد ذي فاصلة عائمة بالصيغة الأسية.
var loadsOf = 55.5;
var thatDay = new DateTime(2010, 2, 25);
$"I had {loadsOf:E} bitcoins on {thatDay:d}, the day I forgot my password."
// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
string.Format(
"I had {0:E} bitcoins on {1:d}, the day I forgot my password.",
loadsOf, thatDay)
// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
يوجد تنسيق قياسي وتنسيق مخصص لكل من الأعداد والتواريخ. ولا يوجد فرق جوهري بين المخصص و_القياسي_ سوى أن لديك فرصة لتكوين سلاسل تنسيق مخصصة من محارف التنسيق. وكلمة "custom" في هذا السياق لا علاقة لها بواجهة ICustomFormatter التي تُستخدم عند تطوير منسّقات مخصصة خاصة بك.
توفر مكتبة الفئات الأساسية (BCL) منسّقين: DateTimeFormatInfo وNumberFormatInfo، و6 مجموعات من سلاسل التنسيق.
وفيما يلي قوائم سلاسل التنسيق المختلفة:
ويمكن تصنيف سلاسل التنسيق الخاصة بـEnum وGUID على أنها قياسية. ومع أن enum وGUID لهما تحميلان زائدان لـToString() يقبلان IFormatProvider، فليس واضحًا أن ذلك يفعل شيئًا.
تحاول المكتبة بث شيء من الاتساق في سلاسل التنسيق (فضلاً عن كونها ممثَّلة كسلاسل نصية). وهذا السعي إلى الاتساق نجده في السلاسل القياسية. وفي الواقع، نادرًا ما يهمك كمطوّر الفرق بين السلاسل القياسية والمخصصة. ومع أن من الجيد، إن كنت تنفذ منسّقات لأصنافك الخاصة، أن تحاكي السلاسل القياسية الموجودة إذا بدا أن أصنافك تتطلب ذلك، فيمكنك تجاهل الفرق تمامًا.
لكل مؤشر ترابط تنفيذ ثقافة افتراضية Thread.CurrentThread.CurrentCulture مغلفة في نسخة من CultureInfo. وتحدد ثقافة مؤشر الترابط كيفية تنسيق التواريخ والأعداد افتراضيًا وفقًا للاختلافات الإقليمية، مثل الاختلاف في صيغة التاريخ المعتادة بين المملكة المتحدة DD/MM/YYYY والولايات المتحدة MM/DD/YYYY.
ويطبّق CultureInfo واجهة IFormatProvider التي يمكن تمريرها إلى تحميلات زائدة معينة من String.Format(). ويمكن استخدام ذلك لتجاوز ثقافة مؤشر الترابط.