سؤال

أنا أبحث عن بعض المؤشرات حول تنفيذ الأحداث المخصصة في VB.NET (Visual Studio 2008 ، .NET 3.5).

أعلم أن الأحداث "العادية" (غير العادية) هي في الواقع مندوبون ، لذلك كنت أفكر في استخدام المندوبين عند تنفيذ حدث مخصص. على الجانب الآخر، أندرو ترويلسن"Pro VB 2008 ومنصة .NET 3.5" يستخدم الكتاب أنواع التجميع في جميع أمثلة الأحداث المخصصة ، و Microsoft's عينة الرموز تطابق هذا الخط من الفكر.

لذا فإن سؤالي هو: ما هي الاعتبارات التي يجب أن أحصل عليها عند اختيار تصميم واحد على الآخر؟ ما هي إيجابيات وسلبيات لكل تصميم؟ أي من هذه تشبه التنفيذ الداخلي للأحداث "العادية"؟

فيما يلي نموذج رمز يوضح التصميمين.

Public Class SomeClass
    Private _SomeEventListeners As EventHandler
    Public Custom Event SomeEvent As EventHandler
        AddHandler(ByVal value As EventHandler)
            _SomeEventListeners = [Delegate].Combine(_SomeEventListeners, value)
        End AddHandler

        RemoveHandler(ByVal value As EventHandler)
            _SomeEventListeners = [Delegate].Remove(_SomeEventListeners, value)
        End RemoveHandler

        RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
            _SomeEventListeners.Invoke(sender, e)
        End RaiseEvent
    End Event

    Private _OtherEventListeners As New List(Of EventHandler)
    Public Custom Event OtherEvent As EventHandler
        AddHandler(ByVal value As EventHandler)
            _OtherEventListeners.Add(value)
        End AddHandler

        RemoveHandler(ByVal value As EventHandler)
            _OtherEventListeners.Remove(value)
        End RemoveHandler

        RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
            For Each handler In _OtherEventListeners
                handler(sender, e)
            Next
        End RaiseEvent
    End Event
End Class
هل كانت مفيدة؟

المحلول

أود أن أقول استخدام المندوب البسيط. ببساطة - هو سابقا (داخليًا) قائمة ، لذا فأنت تكرر الجهد من خلال لفها List<T>. لديك أيضًا النفقات العامة لكائنات القائمة الإضافية والصفائف ، والتي قد تكون فارغة ، لذلك المزيد من التأثير على جمع القمامة وما إلى ذلك.

أيضا ، إذا كنت تفعل الكثير من هذا ، النظر EventHandlerList, الذي يوجد لتوفير وصول فعال إلى متناثر الأحداث - أي حيث تريد فضح الكثير من الأحداث ولكن يمكن أن يكون العديد منها غير معروفة.

المثال الأول هو أقرب بكثير من الأحداث "القياسية" (على الرغم من أنك قد ترغب في مراقبة معالجات غير مخصصة / فارغة عند الاتصال Invoke, ، كما يمكن أن يكون لاغية). بالإضافة إلى ذلك ، لاحظ أن بعض اللغات (بصراحة لا أعرف ما الذي تفعله VB هنا) يطبق المزامنة على الأحداث ، ولكن في الواقع عدد قليل جدًا من الأحداث هل حقا يجب أن تكون آمنة الخيط ، بحيث يمكن أن يكون المبالغة.

تعديل يحدث أيضًا أن هناك ملف وظيفي الفرق بينهما:

  • يعامل نهج المندوب حالات مختلفة بنفس الطريقة / مثيل الهدف على قدم المساواة (لا أعتقد List<T> إرادة)
  • المندوبون المكررون: يزيل المندوب الأخير أولاً ؛ القائمة تزيل الأقدم أولاً
  • المركبات: أضف A ، أضف B ، وإزالة (A+B) - مع مندوب يجب أن ينتج عن ذلك فارغًا / فارغًا ، لكن نهج القائمة سيحتفظ بـ A و B (مع (A+B) إزالة الفشل في العثور على أي شيء)

نصائح أخرى

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

  1. الحصول على قفل ، قم بإنشاء مندوب جديد من القديم ، ولكن مع إضافة حدث أو إزالته ، قم بتعيين مؤشر المندوب على هذا المندوب ، ثم حرر القفل
  2. انسخ مرجعًا إلى المندوب القديم ، وقم بإنشاء مندوب جديد منه ، ولكن مع إضافة حدث أو إزالته ، استخدم interlocked.compareexchang .

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

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

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