سؤال

الركل حول بعض الهياكل الصغيرة أثناء الإجابة هذا المشنور, ، صادفت ما يلي بشكل غير متوقع:

البنية التالية، باستخدام حقل int تعتبر قانونية تمامًا:

struct MyStruct
{ 
    public MyStruct ( int size ) 
    { 
        this.Size = size; // <-- Legal assignment.
    } 

    public int Size; 
}

ومع ذلك، لا يتم تجميع البنية التالية، باستخدام خاصية تلقائية:

struct MyStruct
{ 
    public MyStruct ( int size ) 
    { 
        this.Size = size; // <-- Compile-Time Error!
    } 

    public int Size{get; set;}
}

الخطأ الذي تم إرجاعه هو "لا يمكن استخدام الكائن 'هذا' قبل تعيين كافة الحقول الخاصة به".أعلم أن هذا هو الإجراء القياسي للبنية:يجب تعيين حقل الدعم لأي خاصية مباشرة (وليس عبر موصل مجموعة الخاصية) من داخل مُنشئ البنية.

الحل هو استخدام حقل دعم صريح:

struct MyStruct
{ 
    public MyStruct(int size)
    {
        _size = size;
    }

    private int _size;

    public int Size
    {
        get { return _size; }
        set { _size = value; }
    }
}

(لاحظ أن VB.NET لن يواجه هذه المشكلة، لأنه في VB.NET تتم تهيئة جميع الحقول تلقائيًا إلى 0/null/false عند إنشائها لأول مرة.)

قد يبدو هذا قيدًا مؤسفًا عند استخدام الخصائص التلقائية مع بنيات في C#.بالتفكير من الناحية النظرية، كنت أتساءل عما إذا كان هذا لن يكون مكانًا معقولًا لوجود استثناء يسمح باستدعاء أداة الوصول لمجموعة الخاصية داخل مُنشئ البنية، على الأقل بالنسبة لخاصية تلقائية؟

هذه مشكلة بسيطة، وهي تقريبًا حالة هامشية، لكنني كنت أتساءل عن رأي الآخرين في هذا الأمر...

هل كانت مفيدة؟

المحلول

بدءًا من الإصدار C#6 فصاعدًا:هذا لم يعد مشكلة


بعد أن أصبح Core C# 6، تحتاج إلى استدعاء المُنشئ الافتراضي حتى يعمل هذا:

public MyStruct(int size) : this()
{
    Size = size;
}

المشكلة الأكبر هنا هي أن لديك بنية قابلة للتغيير.هذا هو أبداً فكرة جيدة.سأفعل ذلك:

public int Size { get; private set; }

لا من الناحية الفنية غير قابل للتغيير، ولكن قريب بما فيه الكفاية.

مع الإصدارات الحديثة من C#، يمكنك تحسين هذا:

public int Size { get; }

يمكن هذا الآن فقط يتم تعيينها في المنشئ.

نصائح أخرى

ويمكنك إصلاح هذا من خلال الدعوة لأول مرة المنشئ الافتراضي:

struct MyStruct 
{
    public MyStruct(int size) : this() 
    {
        this.Size = size; // <-- now works
    }

     public int Size { get; set; }
}

هناك حل آخر غامض لهذه المشكلة وهو حل مؤقت Tuple الطبقة في إطار التوسعة المدارة (عبر كرزيستوف كوزميتش):

public struct TempTuple<TFirst, TSecond>
{
    public TempTuple(TFirst first, TSecond second)
    {
        this = new TempTuple<TFirst, TSecond>(); // Kung fu!
        this.First = first;
        this.Second = second;
    }

    public TFirst First { get; private set; }
    public TSecond Second { get; private set; }

(كود المصدر الكامل من Codeplex: Tuple.cs)

وألاحظ أيضًا أن الوثائق الخاصة بـ CS0188 تم التحديث لإضافة:

إذا رأيت هذا الخطأ عند محاولة تهيئة خاصية في مُنشئ الهيكل ، فإن الحل هو تغيير معلمة المنشئ لتحديد حقل الدعم بدلاً من الخاصية نفسها. يجب تجنب الخصائص التي يتم تحسينها تلقائيًا في الهياكل لأنه ليس لها حقل دعم وبالتالي لا يمكن تهيئتها بأي شكل من الأشكال من المنشئ.

لذلك أعتبر أن هذا يعني أن التوجيه الرسمي هو استخدام خصائص النمط القديم في بنياتك عندما تواجه هذه المشكلة، والتي ربما تكون أقل غموضًا (وأكثر قابلية للقراءة) من أي من البديلين الآخرين اللذين تم استكشافهما حتى الآن.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top