يأخذ المعامل (operator) معاملًا أو اثنين أو ثلاثة ويُنتج قيمة: a + b و!done وx ?? fallback. معاملات C# قريبة من معاملات C وJava وJavaScript، لكن بعضها يتصرف بطرق تفاجئ القادمين الجدد، وعلى رأسها قسمة الأعداد الصحيحة وإشارة %.
المعاملات الحسابية
تعمل + و- و* و/ و% مع كل نوع رقمي. يتبع نوع النتيجة المعاملين: قيمتا int تنتجان int، وint مع double ينتجان double.
المخرجات:
22
12
85
3
2
3.4
3.4
3
3.4
قسمة الأعداد الصحيحة تقتطع نحو الصفر. 17 / 5 تساوي 3 و-17 / 5 تساوي -3. وهذا يسبّب خطأً شائعًا جدًا: int percent = done / total * 100; تساوي 0 كلما كان done < total، لأن done / total تساوي 0 أصلًا. اضرب أولًا (done * 100 / total) أو اقسم كـ double.
قسمة عدد صحيح أو decimal على صفر ترمي DivideByZeroException. أما قسمة double على صفر فلا ترمي؛ بل تنتج ما لا نهاية، أو NaN لـ 0.0 / 0.0:
المخرجات:
True
True
False
DivideByZeroException
معامل باقي القسمة والأرقام السالبة
تعيد % باقي القسمة، وتأخذ نتيجتها إشارة المعامل الأول. وهذا يختلف عن Python وعن "mod" الرياضي، اللذين يكونان غير سالبين دائمًا مع مقسوم عليه موجب:
المخرجات:
1
-1
1
2
even
62 min 5 s
Thu
1.5
استخدم الدالة المساعدة Mod كلما أمكن أن يكون الطرف الأول سالبًا وكانت النتيجة فهرسًا: days[(today + offset) % 7] سترمي IndexOutOfRangeException لمجموع سالب. واختبار الأعداد الفردية فيه الفخ نفسه: n % 2 == 1 تساوي false للأعداد الفردية السالبة؛ اختبر n % 2 != 0.
الإسناد والإسناد المركّب والزيادة
= تُسند. تجمع الأشكال المركّبة += و-= و*= و/= و%= و&= و|= و^= و<<= و>>= عملية مع إسناد. تضيف ++ و-- واحدًا أو تطرحانه، ولهما شكل سابق وشكل لاحق يختلفان في القيمة التي يعيدانها:
المخرجات:
14
start, step
a=5 b=7 i=7
4
تُظهر حالة byte غرابة: level = level + 10; لا تُترجم، لأن byte + int نتيجتها int، لكن level += 10; تُترجم، لأن الإسناد المركّب يتضمن تحويلًا ضمنيًا إلى نوع المتغيّر. هذا التحويل يلتفّ عند التجاوز (250 + 10 تصبح 4).
معاملات المقارنة والمعاملات المنطقية
تعيد معاملات المقارنة (== و!= و< و> و<= و>=) قيمة bool. في النصوص تقارن == النص لا المراجع. والمعاملات المنطقية هي ! (النفي) و&& (و) و|| (أو) و^ (أو الحصرية).
المخرجات:
True
no active user
with ||:
evaluated A
with |:
evaluated A
evaluated B
True
تعمل && و|| بدارة قصيرة: لا يُنفَّذ المعامل الثاني إلا حين يمكنه تغيير النتيجة. هذا ما يجعل user != null && user.IsActive آمنة. أما & و| المفردتان على القيم المنطقية فتقيّمان الطرفين دائمًا، ونادرًا ما يكون هذا ما تريده في شرط.
المعاملات البتّية ومعاملات الإزاحة
على الأنواع الصحيحة تعمل & و| و^ و~ على البتات منفردة، وتزيحها << و>>. تُستخدم للأعلام والأقنعة والتجزئة والبروتوكولات منخفضة المستوى:
المخرجات:
3
True
False
101
1024
125
5
-1
لمجموعات الأعلام المسمّاة يكون تعداد بالسمة [Flags] أوضح من الثوابت الصحيحة، وHasFlag أسهل قراءة من القناع. أضافت C# 11 المعامل >>>، وهو إزاحة بلا إشارة تملأ بالأصفار حتى مع الأرقام السالبة.
معاملات null
توجد ثلاثة معاملات للتعامل مع القيم التي قد تكون null:
المخرجات:
Guest
0
5
تعيد a ?? b القيمة a ما لم تكن null، وإلا b. وتعيد a?.Member قيمة null بدل رمي استثناء حين تكون a هي null. وأضافت C# 8 المعامل a ??= b، الذي يُسند b إلى a فقط حين تكون a هي null. هذه مشروحة بعمق في الأنواع القابلة لـ null.
أولوية المعاملات
حين يخلط تعبير عدة معاملات، ترتبط الصفوف الأعلى بقوة أكبر. تُجمَّع المعاملات في الصف نفسه بترتيب ورودها، باستثناء الإسناد و?? و?:، التي تُجمَّع بالترتيب المعاكس (من الأخير إلى الأول). (أما المعاملات نفسها فتُقيَّم دائمًا بترتيب كتابتها.)
| الفئة | المعاملات |
|---|---|
| الأولية | x.y، x?.y، f(x)، a[i]، x++، x--، new، typeof، nameof |
| الأحادية | +x، -x، !x، ~x، ++x، --x، (T)x، await |
| الضربية | *، /، % |
| الجمعية | +، - |
| الإزاحة | <<، >>، >>> |
| العلائقية واختبار النوع | <، >، <=، >=، is، as |
| المساواة | ==، != |
| AND البتّي | & |
| XOR البتّي | ^ |
| OR البتّي | | |
| AND الشرطي | && |
| OR الشرطي | || |
| دمج null | ?? |
| الشرطي | c ? a : b |
| الإسناد وlambda | =، +=، -=، ??=، =>، وسائر الأشكال المركّبة |
نتيجتان تستحقان المعرفة: a + b * c تضرب أولًا، وx & mask == 0 تقارن أولًا (== ترتبط بقوة أكبر من &)، فمعناها x & (mask == 0) ولا تُترجم مع الأعداد الصحيحة. اكتب (x & mask) == 0. الأقواس لا تكلّف شيئًا وتجعل القصد واضحًا.
التحميل الزائد للمعاملات
تستطيع أنواعك تعريف معنى المعاملات. بهذا تدعم decimal وDateTime وTimeSpan المعاملين + و<:
المخرجات:
33.49
True
يجب أن تكون المعاملات public static، وبعضها يأتي في أزواج إلزامية: تعريف < يتطلب >، و== يتطلب !=. ومع تعريف == يحذّر المترجم أيضًا حتى تتجاوز Equals وGetHashCode بما يطابقه. لا تحمّل المعاملات تحميلًا زائدًا إلا حيث يكون المعنى بديهيًا، كما مع الأرقام والمتجهات والمال.
الأسئلة الشائعة
ماذا يفعل % في C#؟
% معامل باقي القسمة: 17 % 5 تساوي 2. تأخذ النتيجة إشارة المعامل الأول، فتكون -7 % 3 مساوية لـ -1، لا 2 كما في Python. لنتيجة غير سالبة دائمًا، كما تحتاج عند لفّ فهرس، اكتب ((a % n) + n) % n. ويعمل أيضًا مع double وdecimal: 7.5 % 2 تساوي 1.5.
لماذا تساوي 7 / 2 القيمة 3 في C#؟
حين يكون المعاملان عددين صحيحين، تنفّذ / قسمة صحيحة وتتخلّص من الجزء الكسري، مقتطعة نحو الصفر. اجعل أحد المعاملين قيمة عشرية عائمة أو decimal لتحصل على نتيجة كسرية: 7 / 2.0 تساوي 3.5، و(double)a / b تحوّل قبل القسمة، و7m / 2 تساوي 3.5 كـ decimal.
ما الفرق بين && و& في C#؟
&& هو AND الشرطي: إن كان الطرف الأول false لا يُقيَّم الطرف الثاني. أما & على القيم المنطقية فيقيّم الطرفين دائمًا، وعلى الأعداد الصحيحة هو AND البتّي. استخدم && و|| للشروط، وخاصة الحراسات مثل user != null && user.IsActive، التي كانت سترمي NullReferenceException مع &.
ما الفرق بين i++ و++i في C#؟
كلاهما يضيف 1 إلى i. التعبير i++ يعطي القيمة القديمة، و++i يعطي القيمة الجديدة. في سطر وحده (i++;) لا فرق. لا يهمّ الفرق إلا حين تُستخدم النتيجة، كما في int a = i++;، ولهذا تبقي أدلة أسلوب كثيرة الزيادات في سطر مستقل.
ما هي أولوية المعاملات في C#؟
من الأعلى إلى الأدنى: الأولية (x.y وf(x) وa[i] وx++)، الأحادية (! و- و++x والتحويلات)، الضربية (* / %)، الجمعية (+ -)، الإزاحات، العلائقية (< > <= >= is as)، المساواة (== !=)، ثم & و^ و| و&& و|| و??، ثم الشرطي ?:، وأخيرًا الإسناد. عند الشك أضف أقواسًا.