لماذا من الضروري استدعاء :this() على البنية لاستخدام الخصائص التلقائية في c#؟

StackOverflow https://stackoverflow.com/questions/272153

سؤال

إذا قمت بتحديد بنية في C# باستخدام خصائص تلقائية مثل هذا:

public struct Address
{
    public Address(string line1, string line2, string city, string state, string zip)
    {
        Line1 = line1;
        Line2 = line2;
        City = city;
        State = state;
        Zip = zip;
    }

    public string Line1 { get; protected set; }
    public string Line2 { get; protected set; }
    public string City { get; protected set; }
    public string State { get; protected set; }
    public string Zip { get; protected set; }
}

عندما أحاول إنشاء الملف، تظهر لي رسالة خطأ في التجميع تقول The 'this' object cannot be used before all of its fields are assigned to.يمكن حل هذه المشكلة عن طريق تغيير المنشئ لإجراء مكالمة متسلسلة إلى المنشئ الافتراضي مثل هذا:

public Address(string line1, string line2, string city, string state, string zip): this()
{
    Line1 = line1;
    Line2 = line2;
    City = city;
    State = state;
    Zip = zip;
}

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

نرحب بأي وجميع معالجات IL لإثبات نظريتي أو دحضها.

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

المحلول

ملحوظة:اعتبارًا من C# 6، هذا غير مطلوب - ولكن يجب أن تستخدم خصائص للقراءة فقط يتم تنفيذها تلقائيًا مع C# 6 على أي حال...

this() يتأكد من أن الحقول قد تم تعيينها بالتأكيد بقدر ما يتعلق الأمر بالمترجم - فهو يضبط جميع الحقول على قيمها الافتراضية.يجب أن يكون لديك بنية مبنية بالكامل قبل أن تتمكن من البدء في الوصول أي ملكيات.

إنه أمر مزعج، ولكن هذا هو الحال.هل أنت متأكد من أنك تريد حقًا أن يكون هذا هيكلًا؟ولماذا نستخدم أداة ضبط محمية على البنية (التي لا يمكن استخلاصها منها)؟

نصائح أخرى

وخاصية ليست أكثر من مجرد تغليف من طريقة Get و / أو أسلوب Set. وCLR ديه الفوقية مما يدل على أن أساليب معينة ينبغي اعتبار كونه الخصائص، وهذا يعني المجمعين يجب السماح لبعض التركيبات التي فإنه لن تسمح مع الأساليب. على سبيل المثال، إذا X هو خاصية للقراءة والكتابة من Foo، سوف مترجم ترجمة Foo.X += 5 إلى Foo.SET_X_METHOD(Foo.GET_X_METHOD() + 5) (على الرغم من تسمية أساليب مختلفة، ولا يمكن الوصول إليها بالاسم عموما).

وعلى الرغم من أن autoproperty تنفذ زوج من طرق الحصول على / مجموعة التي الوصول إلى الحقل الخاص في مثل هذه الطريقة في التصرف أكثر أو أقل مثل حقل، من وجهة نظر أي رمز خارج العقار، وautoproperty هو زوج من الحصول على وسائل / مجموعة تماما مثل أي ممتلكات أخرى. ونتيجة لذلك، تتم ترجمة عبارة مثل Foo.X = 5; كما Foo.SET_X_METHOD(5). منذ # مترجم C يرى أن مجرد أنها دعوة طريقة، ومنذ الأساليب لا تتضمن أية بيانات تعريف للإشارة إلى ما هي الحقول التي القراءة أو الكتابة، فإن المترجم يمنع استدعاء الأسلوب إلا إذا كان يعرف كل ميدان من ميادين لقد كتب Foo.

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

وعلاوة على ذلك، فإن الاختلافات في الأداء بين الحقول والممتلكات هو أكبر بكثير مع الهياكل الكبيرة مما هو عليه مع أنواع الطبقة. في الواقع، فإن الكثير من توصية لتجنب الهياكل الكبيرة هو نتيجة لهذا الاختلاف. يمكن الهياكل الكبيرة يكون في الواقع فعالة جدا، إذا كان أحد يتجنب نسخها دون داع. حتى لو كان واحد من HexDecet<HexDecet<HexDecet<Integer>>> هيكل هائلة، حيث الواردة HexDecet<T> تتعرض الحقول F0..F15 من نوع T، عبارة مثل Foo = MyThing.F3.F6.F9; ببساطة تتطلب قراءة صحيحة واحدة من MyThing وتخزينها لFoo، على الرغم من شأنه MyThing التي كتبها ضخمة وفقا للمعايير البنية ( 4096 الأعداد الصحيحة الاحتلال 16K). بالإضافة إلى ذلك، يمكن للمرء أن تحديث هذا العنصر بسهولة جدا، على سبيل المثال MyThing.F3.F6.F9 += 26;. على النقيض من ذلك، إذا كانت F0..F15 لصناعة السيارات في الخصائص، فإن Foo = MyThing.F3.F6.F9 بيان تتطلب نسخ 1K البيانات من MyThing.F3 إلى المؤقتة (يطلق عليه temp1، ثم 64 بايت من البيانات من temp1.F6 إلى temp2) قبل الحصول أخيرا في جميع أنحاء لقراءة 4 بايت البيانات من temp2.F9. إك. والأسوأ من ذلك، في محاولة لإضافة 26 إلى القيمة في MyThing.F3.F6.F9 يتطلب شيء من هذا القبيل var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1;.

والعديد من الشكاوى طويلة الأمد حول "أنواع بنية قابلة للتغيير" هي في الواقع شكاوى حول أنواع هيكل مع القراءة / الكتابة خصائص. ببساطة استبدال خصائص مع الحقول والمشاكل تذهب بعيدا.

وPS: هناك أوقات يمكن أن يكون مفيدا أن يكون لها هيكل الذي الوصول إلى كائن الفئة التي تحمل إشارة خصائص. على سبيل المثال، سيكون من الجميل أن يكون لديك نسخة من فئة ArraySegment<T> الذي يسمح لأحد أن يقول Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9;، ويكون البيان الأخير إضافة إلى تسعة العنصر (25 + 6) من foo. في الإصدارات القديمة من C # واحد يمكن ان نفعل ذلك. وللأسف، فإن الاستخدام المتكرر للautoproperties في إطار حيث سيكون قد ادى مجالات أكثر ملاءمة للشكاوى واسعة النطاق حول ع مترجم السماحاضعي roperty ليتم استدعاؤها دون جدوى على هياكل للقراءة فقط. وبالتالي، استدعاء أي اضع الملكية على هيكل للقراءة فقط ممنوع الآن، أم لا واضع الملكية من شأنه أن يعدل في الواقع أي مجالات البنية. إذا كان الناس قد امتنع ببساطة من صنع البنيات قابلة للتغيير عبر اضعي الملكية (مما الحقول يمكن الوصول إليه مباشرة عندما كان التحولية المناسب) المجمعين أن أبدا من أن تنفيذ هذا التقييد.

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