سؤال

نحن نناقش حاليًا ما إذا كانت أساليب الامتداد في .NET سيئة أم لا.أو تحت أي ظروف يمكن أن تؤدي أساليب الامتداد إلى أخطاء يصعب العثور عليها أو تتصرف بأي طريقة أخرى بشكل غير متوقع.

لقد توصلنا إلى:

  • كتابة طريقة تمديد للأنواع التي ليست تحت سيطرتك (على سبيل المثال.يعد توسيع DirectoryInfo باستخدام GetTotalSize()، وما إلى ذلك) أمرًا سيئًا، لأن مالك واجهة برمجة التطبيقات (API) يمكنه تقديم طريقة تخفي امتدادنا - وقد يكون له حالات حافة مختلفة.على سبيل المثال، سيتم ترجمة اختبار القيمة الخالية في إحدى طرق الامتداد تلقائيًا إلى NullReferenceException إذا لم تعد طريقة الامتداد مستخدمة بسبب الاختباء.

سؤال:

  • هل هناك مواقف خطيرة أخرى غير "الاختباء" لا نفكر فيها؟

يحرر:

حالة أخرى خطيرة للغاية.لنفترض أن لديك طريقة تمديد:

namespace Example.ExtensionMethods
{
    public static class Extension
    {
        public static int Conflict(this TestMe obj)
        {
            return -1;
        }
    }
}

واستخدمه:

namespace Example.ExtensionMethods.Conflict.Test
{
    [TestFixture]
    public class ConflictExtensionTest
    {
        [Test]
        public void ConflictTest()
        {
            TestMe me = new TestMe();
            int result = me.Conflict();
            Assert.That(result, Is.EqualTo(-1));
        }
    }
}

لاحظ أن مساحة الاسم التي تستخدمها أطول.

الآن يمكنك الرجوع إلى ملف dll بهذا:

namespace Example.ExtensionMethods.Conflict
{
    public static class ConflictExtension
    {
        public static int Conflict(this TestMe obj)
        {
            return 1;
        }
    }
}

وسوف يفشل الاختبار الخاص بك!سيتم تجميعه بدون خطأ في المترجم.فإنه سوف ببساطة تفشل.بدون الحاجة إلى تحديد "استخدام example.ExtensionMethods.Conflict".سوف يقوم المترجم بالتعرف على اسم مساحة الاسم والعثور على example.ExtensionMethods.Conflict.ConflictExtension قبل example.ExtensionMethods.Extension وسيستخدم ذلك دون الشكوى من طرق التمديد الغامضة.يا للرعب!

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

المحلول

بعض الفضول:

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

(يحرر) وبالطبع هناك "Nullable<T>/new()"قنبلة (انظر هنا)...

نصائح أخرى

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

كسر واحد وجدناه للتو في المزيدLINQ مشروع:إذا كتبت طريقة تمديد عامة، فمن المستحيل التأكد من أنها ستعمل مع جميع الأنواع.لدينا طريقة بهذا التوقيع:

public static IEnumerable<T> Concat<T>(this T head, IEnumerable<T> tail)

لا يمكنك استخدام ذلك مع:

"foo".Concat(new [] { "tail" });

بسبب string.Concat طريقة...

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

هناك شيء واحد يمكنك القيام به للتأكد من أن طرق الامتداد لا تتعارض مع الطرق الأخرى (امتداد أو غير ذلك) وهو الاستخدام FxCop مع قواعد مثل منع تكرار تواقيع أسلوب التمديد.

في البداية، أعتقد أن صياغتك مضللة بعض الشيء.أعتبر أنك تتحدث عن "الأنواع" وليس "الأشياء".

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

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

ما هي طرق تمديد مكالمات .Net هي أيضًا شكل محدود أ MonkeyPatching (حاول تجاهل صخب PHP هناك).

ينبغي أن يوفر لك ذلك بعض المواد لمناقشتك.

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