Struct أو Class في C#: متى يختار المبتدئ أيهما؟

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

Struct أم Class في C#: جدل أبدي بين المبتدئين والمحترفين

\n\n

هل تساءلت يوماً لماذا يوجد في C# طريقتان متشابهتان جداً لإنشاء نوع البيانات الخاص بك — class و struct؟ ولماذا على Stack Overflow سؤال «متى يجب أن أستخدم struct بدلاً من class في C#؟» يجمع آلاف المشاهدات ومئات الإجابات؟ الأمر أن وراء البساطة الظاهرة يكمن فارق دقيق يمكنه إما تسريع برنامجك أو تحويله إلى أرض خصبة للأخطاء.

\n\n

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

\n\n

الفرق الرئيسي: المكدس أم الكومة؟

\n\n

أهم نقطة يجب فهمها هي أنواع القيم (value types) و أنواع المراجع (reference types).

\n\n
    \n
  • Class — نوع مرجعي. يتم تخزين الكائن في الكومة المُدارة (heap)، والمتغير يحتوي فقط على مرجع (عنوان) لهذا الكائن.
  • \n
  • Struct — نوع قيمة (value type). المتغير يخزن البيانات نفسها مباشرة في المكدس (stack) أو داخل كائن آخر.
  • \n
\n\n

يبدو الأمر تجريدياً؟ دعنا نأخذ مثالاً. تخيل أن البيانات هي كتاب. Class هو اسم الكتاب ورقم الرف الذي يوضع عليه في المكتبة. Struct هو الكتاب نفسه الذي تحمله في جيبك. عندما تمرر class إلى دالة، فأنت تمرر رقم الرف. عندما تمرر struct — فأنت تعطي نسخة من الكتاب.

\n\n

مثال كود: class vs struct

\n\n
public class PointClass\n{\n    public int X { get; set; }\n    public int Y { get; set; }\n\n    public PointClass(int x, int y)\n    {\n        X = x;\n        Y = y;\n    }\n}\n\npublic struct PointStruct\n{\n    public int X { get; set; }\n    public int Y { get; set; }\n\n    public PointStruct(int x, int y)\n    {\n        X = x;\n        Y = y;\n    }\n}\n\n// الاستخدام\nvar pointClass = new PointClass(10, 20);\nvar pointStruct = new PointStruct(10, 20);\n\n// التمرير إلى دالة\nvoid ModifyPointClass(PointClass p) { p.X = 100; }\nvoid ModifyPointStruct(PointStruct p) { p.X = 100; }\n\nModifyPointClass(pointClass);   // pointClass.X سيصبح 100\nModifyPointStruct(pointStruct); // pointStruct.X سيبقى 10 — نسخة!\n
\n\n

أرأيت؟ يتم نسخ struct عند تمريرها. هذا هو الفارق الرئيسي الذي يحدد متى يجب استخدامها.

\n\n

متى يكون struct صديقك: 3 حالات قوية

\n\n

توصي Microsoft باستخدام struct إذا كان نوع البيانات الخاص بك يستوفي جميع الشروط التالية:

\n\n

1. البيانات صغيرة وبسيطة

\n

Struct مثالية لمجموعات البيانات الصغيرة (يُوصى بألا تزيد عن 16-24 بايت). على سبيل المثال، نقطة، لون، متجه، عدد مركب، إحداثيات.

\n\n
public struct RgbColor\n{\n    public byte R { get; }\n    public byte G { get; }\n    public byte B { get; }\n\n    public RgbColor(byte r, byte g, byte b)\n    {\n        R = r;\n        G = g;\n        B = b;\n    }\n}\n
\n\n

لماذا؟ لأن struct الصغيرة تُنسخ بسرعة، والتخزين في المكدس يقلل الضغط على جامع القمامة (GC).

\n\n

2. الكائنات تعيش لفترة قصيرة ولا تتغير

\n

إذا كانت بياناتك هي قيم غير قابلة للتغيير (immutable)، فإن struct خيار ممتاز. على سبيل المثال، إحداثيات على الخريطة: أنت لا تغير النقطة، بل تنشئ نقطة جديدة.

\n\n
public struct GeoLocation\n{\n    public double Latitude { get; }\n    public double Longitude { get; }\n\n    public GeoLocation(double lat, double lon)\n    {\n        Latitude = lat;\n        Longitude = lon;\n    }\n\n    public GeoLocation MoveNorth(double meters)\n    {\n        // نعيد مثيلاً جديداً، لا نغير القديم\n        return new GeoLocation(Latitude + meters / 111111.0, Longitude);\n    }\n}\n
\n\n

3. الأداء حرج

المدونات

توصيات الكتب