C#: المتغيرات وأنواع البيانات

تخيل أن المتغير عبارة عن صندوق عليه ملصق: الملصق هو الاسم، والصندوق يحتوي على البيانات. واختيار الحجم والنوع المناسبين للصندوق يضمن أمان بياناتك وكفاءتها.

1. إعلان المتغيرات وتعيين قيمها الأولية

لغة C# هي لغة ذات أنواع محددة بشكل صارم، لذا يجب عليك تحديد النوع عند إعلان متغير (أو استخدام var للسماح للمترجم باستنتاجه):

CSHARP
int age;
age = 25;

string name = "Alice";
double score = 95.5;

يمكنك أيضًا تعريف متغيرات متعددة من نفس النوع في سطر واحد:

CSHARP
int x = 1, y = 2, z = 3;

تحذير: لا تسمح لغة C# باستخدام المتغيرات المحلية غير المُهيأة؛ حيث سيُصدر المُترجم خطأً.


2. قواعد التسمية

تفرض لغة C# قواعد صارمة لتسمية المتغيرات:

(1) camelCase و PascalCase

تتضمن لغة C# قاعدتين أساسيتين لتسمية المتغيرات:

نوع المعرّف النمط أمثلة
المتغيرات المحلية، الحقول camelCase studentName، totalCount
الطرق، الفئات، الخصائص PascalCase CalculateSum، Student

نصيحة: أسلوب camelCase: الكلمة الأولى بحرف صغير، والكلمات التالية بأحرف كبيرة؛ أسلوب PascalCase: كل كلمة بحرف كبير.

CSHARP
int studentAge = 18;
double averageScore = 87.5;
string homeAddress = "Beijing";

3. أنواع الأعداد الصحيحة

توفر لغة C# 8 أنواع من الأعداد الصحيحة، تشمل الأعداد الموقعة وغير الموقعة على حد سواء:

النوع البايتات النطاق اللاحقة
sbyte 1 -128 ~ 127
byte 1 0 ~ 255
short 2 -32,768 ~ 32,767
ushort 2 0 ~ 65,535
int 4 -2,147,483,648 ~ 2,147,483,647
uint 4 0 ~ 4,294,967,295 U
long 8 -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 L
ulong 8 0 ~ 18,446,744,073,709,551,615 UL

نصيحة: على عكس لغة Java، تحتوي لغة C# على أنواع أعداد صحيحة غير موقعة (byte، ushort، uint، ulong). لاحظ أن byte في لغة C# غير موقّعة، في حين أن النسخة الموقّعة هي sbyte.

▶ مثال

CSHARP
sbyte sb = -100;
byte b = 200;
short s = -30000;
ushort us = 60000;
int i = 100000;
uint ui = 3000000000U;
long l = 9000000000000000000L;
ulong ul = 18000000000000000000UL;

Console.WriteLine($"sbyte:  {sb}");
Console.WriteLine($"byte:   {b}");
Console.WriteLine($"short:  {s}");
Console.WriteLine($"ushort: {us}");
Console.WriteLine($"int:    {i}");
Console.WriteLine($"uint:   {ui}");
Console.WriteLine($"long:   {l}");
Console.WriteLine($"ulong:  {ul}");
▶ جرّب الكود
TEXT 📖 للعرض فقط
sbyte:  -100
byte:   200
short:  -30000
ushort: 60000
int:    100000
uint:   3000000000
long:   9000000000000000000
ulong:  18000000000000000000

4. أنواع الأرقام العائمة

النوع البايتات الدقة النطاق (تقريبًا) اللاحقة حالة الاستخدام
float 4 7 أرقام +/-1.5×10⁻⁴⁵ ~ +/-3.4×10³⁸ f الرسومات والألعاب
double 8 15-16 رقمًا +/-5.0×10⁻³²⁴ ~ +/-1.7×10³⁰⁸ d (الافتراضي) الحوسبة العلمية
decimal 16 28-29 رقمًا +/-1.0×10⁻²⁸ ~ +/-7.9×10²⁸ m المبالغ المالية

تحذير: القيم العشرية الثابتة تكون double بشكل افتراضي. يجب عليك إضافة لاحقة عند التعيين إلى float أو decimal، وإلا فإن المُترجم سيُصدر خطأً.

CSHARP
float f = 3.14f;
double d = 3.14;
decimal m = 3.14m;

Console.WriteLine($"float:   {f}");
Console.WriteLine($"double:  {d}");
Console.WriteLine($"decimal: {m}");
TEXT 📖 للعرض فقط
float:   3.14
double:  3.14
decimal: 3.14

نصيحة: تم تصميم decimal لإجراء الحسابات المالية وتجنب الأخطاء الثنائية في الأرقام العائمة. على سبيل المثال، 0.1 + 0.2 لا يتطابق تمامًا مع 0.3 عند استخدامه مع double، ولكنه يتطابق تمامًا مع decimal.


5. النوع bool

يحتوي bool على قيمتين فقط: true وfalse، ويشغل 1 بايت.

تحذير: على عكس لغة C، لا يمكن تحويل bool في لغة C# ضمناً إلى أعداد صحيحة أو منها. if(1) غير صحيح؛ يجب عليك كتابة if(true) أو if(x != 0).

CSHARP
bool isReady = true;
bool isEmpty = false;

Console.WriteLine($"isReady:  {isReady}");
Console.WriteLine($"isEmpty:  {isEmpty}");
TEXT 📖 للعرض فقط
isReady:  True
isEmpty:  False

6. نوع char

يُعد char في لغة C# حرفًا من أحرف يونيكود مكونًا من بايتين، وليس حرفًا من أحرف ASCII مكونًا من بايت واحد كما هو الحال في لغة C.

CSHARP
char ch1 = 'A';
char ch2 = '\u03a9';

Console.WriteLine($"ch1: {ch1}");
Console.WriteLine($"ch2: {ch2}");
Console.WriteLine($"ch1 code: {(int)ch1}");
Console.WriteLine($"ch2 code: {(int)ch2}");
TEXT 📖 للعرض فقط
ch1: A
ch2: Ω
ch1 code: 65
ch2 code: 937

نصيحة: يستخدم char علامات الاقتباس المفردة 'A'، بينما يستخدم string علامات الاقتباس المزدوجة "A" — وهما نوعان مختلفان تمامًا.


7. نوع السلسلة

string هو نوع مرجعي يمثل تسلسلًا ثابتًا من أحرف يونيكود.

CSHARP
string greeting = "Hello";
string name = "World";
string message = greeting + ", " + name + "!";

Console.WriteLine(message);
Console.WriteLine($"Length: {message.Length}");
TEXT 📖 للعرض فقط
Hello, World!
Length: 13

تحذير: string هو نوع مرجعي، وقيمته الافتراضية هي null (وليس سلسلة فارغة ""). سيؤدي الوصول إلى سلسلة null إلى إثارة استثناء NullReferenceException.


8. var: التعيين الضمني للنوع

قدمت لغة C# 3.0 الكلمة الرئيسية var، التي تتيح للمترجم استنتاج النوع من القيمة الأولية:

CSHARP
var count = 42;
var price = 9.99m;
var label = "hello";
var flag = true;

Console.WriteLine(count.GetType().Name);
Console.WriteLine(price.GetType().Name);
Console.WriteLine(label.GetType().Name);
Console.WriteLine(flag.GetType().Name);
TEXT 📖 للعرض فقط
Int32
Decimal
String
Boolean

تحذير: لا تعني var «أي نوع» — حيث يتم تحديد نوع المتغير في وقت التحويل البرمجي ويجب تهيئته. ما يلي غير صحيح:

CSHARP
var x;
var x = null;

نصيحة: استخدم var عندما تكون أسماء الأنواع طويلة أو عندما يكون النوع واضحًا من السياق. تجنب الإفراط في استخدامه، لأنه قد يقلل من سهولة القراءة.


9. sizeof — التحقق من حجم النوع

تُرجع الدالة sizeof عدد البايتات التي يشغلها نوع معين. ويمكن استخدامها مباشرةً مع الأنواع الأولية؛ أما الأنواع الأخرى فتتطلب سياق unsafe.

▶ مثال

CSHARP
Console.WriteLine($"sbyte:    {sizeof(sbyte)} bytes");
Console.WriteLine($"byte:     {sizeof(byte)} bytes");
Console.WriteLine($"short:    {sizeof(short)} bytes");
Console.WriteLine($"ushort:   {sizeof(ushort)} bytes");
Console.WriteLine($"int:      {sizeof(int)} bytes");
Console.WriteLine($"uint:     {sizeof(uint)} bytes");
Console.WriteLine($"long:     {sizeof(long)} bytes");
Console.WriteLine($"ulong:    {sizeof(ulong)} bytes");
Console.WriteLine($"float:    {sizeof(float)} bytes");
Console.WriteLine($"double:   {sizeof(double)} bytes");
Console.WriteLine($"decimal:  {sizeof(decimal)} bytes");
Console.WriteLine($"char:     {sizeof(char)} bytes");
Console.WriteLine($"bool:     {sizeof(bool)} bytes");
▶ جرّب الكود
TEXT 📖 للعرض فقط
sbyte:    1 bytes
byte:     1 bytes
short:    2 bytes
ushort:   2 bytes
int:      4 bytes
uint:     4 bytes
long:     8 bytes
ulong:    8 bytes
float:    4 bytes
double:   8 bytes
decimal:  16 bytes
char:     2 bytes
bool:     1 bytes

10. الثوابت (const)

استخدم const لإعلان الثوابت في وقت التحويل البرمجي التي لا يمكن تغيير قيمها. ويجب تهيئة قيمها عند الإعلان:

CSHARP
const double Pi = 3.14159265358979;
const int MaxRetry = 3;
const string AppName = "MyApp";

Console.WriteLine($"Pi = {Pi}");
Console.WriteLine($"MaxRetry = {MaxRetry}");
Console.WriteLine($"AppName = {AppName}");
TEXT 📖 للعرض فقط
Pi = 3.14159265358979
MaxRetry = 3
AppName = MyApp

تحذير: عادةً ما تستخدم أسماء const أسلوب كتابة PascalCase. يجب أن تكون القيمة قابلة للتحديد في وقت التحويل البرمجي، ولا يجوز أن تكون متغيرًا أو نتيجة استدعاء دالة.

نصيحة: إذا كنت بحاجة إلى «ثابت» يتم تحديده أثناء وقت التشغيل، فاستخدم حقل readonly بدلاً من ذلك.


11. القيم الافتراضية للأنواع

لكل نوع قيمة افتراضية في حالة عدم تعيين قيمة أولية له:

النوع القيمة الافتراضية
sbyte / byte / short / ushort / int / uint / long / ulong 0
float 0.0f
double 0.0d
decimal 0.0m
char '\0'
bool false
string null
أي نوع مرجعي null

▶ مثال

CSHARP
int defaultInt = default;
bool defaultBool = default;
char defaultChar = default;
string defaultString = default;
double defaultDouble = default;

Console.WriteLine($"int:    [{defaultInt}]");
Console.WriteLine($"bool:   [{defaultBool}]");
Console.WriteLine($"char:   [{(int)defaultChar}]");
Console.WriteLine($"string: [{defaultString}]");
Console.WriteLine($"double: [{defaultDouble}]");
▶ جرّب الكود
TEXT 📖 للعرض فقط
int:    [0]
bool:   [False]
char:   [0]
string: []
double: [0]

نصيحة: يمكن للكلمة الرئيسية default الحصول على القيمة الافتراضية لأي نوع، وهي شائعة بشكل خاص في الأنواع العامة: default(T).


12. أنواع القيم مقابل أنواع المراجع — مقدمة

تنقسم أنواع C# إلى فئتين رئيسيتين:

الفئة التخزين سلوك التخصيص الأنواع النموذجية
نوع القيمة المكدس (عادةً) نسخ القيمة int، bool، char، decimal، struct، enum
نوع المرجع الذاكرة الديناميكية نسخ المرجع (العنوان) string، class، object، المصفوفات
CSHARP
int a = 10;
int b = a;
b = 20;
Console.WriteLine($"a = {a}, b = {b}");

string s1 = "hello";
string s2 = s1;
s2 = "world";
Console.WriteLine($"s1 = {s1}, s2 = {s2}");
TEXT 📖 للعرض فقط
a = 10, b = 20
s1 = hello, s2 = world

تحذير: لم يتحول s1 إلى "world" لأن string غير قابل للتغيير — فـ s2 = "world" لا يُعدِّل الكائن الأصلي، بل يجعل s2 يشير إلى كائن جديد. تقوم عملية التعيين لنوع القيمة بنسخ القيمة الفعلية، بينما تقوم عملية التعيين لنوع المرجع بنسخ المرجع. ومع ذلك، فإن ثبات string يجعلها تتصرف كنوع قيمة.


❓ أسئلة شائعة

س ما الفرق بين var وdynamic؟
ج var يحدد النوع في وقت التحويل البرمجي ويتميز بالأمان من حيث النوع؛ أما dynamic فيحدد النوع في وقت التشغيل، ولا يخضع لفحص النوع في وقت التحويل البرمجي، ويكون أداؤه أقل، كما أنه أكثر عرضة للأخطاء.
س لماذا يُعد decimal أفضل من double في الحسابات النقدية؟
ج يستخدم decimal التخزين العشري، لذا يمكن تمثيل 0.1 بدقة؛ بينما يستخدم double التخزين الثنائي، حيث لا يمكن تمثيل 0.1 بدقة، مما يؤدي إلى أخطاء تقريب تراكمية.
س هل string نوع قيمة أم نوع مرجعي؟
ج string هو نوع مرجعي، ولكن نظرًا لكونه غير قابل للتغيير، فإن عملية التعيين تتسم بدلالات القيمة — أي أن تعديل متغير ما لا يؤثر على متغير آخر.
س ما الفرق بين const وreadonly؟
ج const هو ثابت وقت التحويل البرمجي الذي يجب تعيين قيمته عند الإعلان عنه، وهو ثابت ضمنيًا؛ أما readonly فهو ثابت وقت التشغيل يمكن تعيينه في منشئ وقد يختلف من مثيل لآخر.

📖 ملخص

📝 تمارين

  1. قم بتعريف متغير int باسم age وقيمته هي عمرك، ومتغير string باسم name وقيمته هي اسمك، ثم اعرض كليهما
  2. احسب 0.1 + 0.2 باستخدام float وdouble وdecimal على التوالي، وقارن ما إذا كانت النتائج تساوي 0.3 تمامًا
  3. استخدم sizeof لطباعة أحجام البايتات الخاصة بـ int وdouble وchar وbool
  4. حدد const double Pi = 3.14159265 واحسب مساحة الدائرة التي يبلغ نصف قطرها 5، ثم اعرض النتيجة
  5. استخدم الكلمة الرئيسية default للحصول على القيم الافتراضية لـ int وbool وchar وstring وعرضها
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%