11using System ;
22using System . Collections ;
3+ using System . Diagnostics ;
34using System . Reflection ;
45
56namespace Python . Runtime
@@ -10,124 +11,16 @@ namespace Python.Runtime
1011 [ Serializable ]
1112 internal class EventObject : ExtensionType
1213 {
13- internal string name ;
14- internal PyObject ? unbound ;
15- internal EventInfo info ;
16- internal Hashtable ? reg ;
14+ internal readonly string name ;
15+ internal readonly EventHandlerCollection reg ;
1716
1817 public EventObject ( EventInfo info )
1918 {
19+ Debug . Assert ( ! info . AddMethod . IsStatic ) ;
2020 this . name = info . Name ;
21- this . info = info ;
21+ this . reg = new EventHandlerCollection ( info ) ;
2222 }
2323
24-
25- /// <summary>
26- /// Register a new Python object event handler with the event.
27- /// </summary>
28- internal bool AddEventHandler ( BorrowedReference target , PyObject handler )
29- {
30- object ? obj = null ;
31- if ( target != null )
32- {
33- var co = ( CLRObject ) GetManagedObject ( target ) ! ;
34- obj = co . inst ;
35- }
36-
37- // Create a true delegate instance of the appropriate type to
38- // wrap the Python handler. Note that wrapper delegate creation
39- // always succeeds, though calling the wrapper may fail.
40- Type type = info . EventHandlerType ;
41- Delegate d = PythonEngine . DelegateManager . GetDelegate ( type , handler ) ;
42-
43- // Now register the handler in a mapping from instance to pairs
44- // of (handler hash, delegate) so we can lookup to remove later.
45- // All this is done lazily to avoid overhead until an event is
46- // actually subscribed to by a Python event handler.
47- if ( reg == null )
48- {
49- reg = new Hashtable ( ) ;
50- }
51- object key = obj ?? info . ReflectedType ;
52- var list = reg [ key ] as ArrayList ;
53- if ( list == null )
54- {
55- list = new ArrayList ( ) ;
56- reg [ key ] = list ;
57- }
58- list . Add ( new Handler ( Runtime . PyObject_Hash ( handler ) , d ) ) ;
59-
60- // Note that AddEventHandler helper only works for public events,
61- // so we have to get the underlying add method explicitly.
62- object [ ] args = { d } ;
63- MethodInfo mi = info . GetAddMethod ( true ) ;
64- mi . Invoke ( obj , BindingFlags . Default , null , args , null ) ;
65-
66- return true ;
67- }
68-
69-
70- /// <summary>
71- /// Remove the given Python object event handler.
72- /// </summary>
73- internal bool RemoveEventHandler ( BorrowedReference target , BorrowedReference handler )
74- {
75- if ( reg == null )
76- {
77- Exceptions . SetError ( Exceptions . ValueError , "unknown event handler" ) ;
78- return false ;
79- }
80-
81- object ? obj = null ;
82- if ( target != null )
83- {
84- var co = ( CLRObject ) GetManagedObject ( target ) ! ;
85- obj = co . inst ;
86- }
87-
88- nint hash = Runtime . PyObject_Hash ( handler ) ;
89- if ( hash == - 1 && Exceptions . ErrorOccurred ( ) )
90- {
91- return false ;
92- }
93-
94- object key = obj ?? info . ReflectedType ;
95- var list = reg [ key ] as ArrayList ;
96-
97- if ( list == null )
98- {
99- Exceptions . SetError ( Exceptions . ValueError , "unknown event handler" ) ;
100- return false ;
101- }
102-
103- object ? [ ] args = { null } ;
104- MethodInfo mi = info . GetRemoveMethod ( true ) ;
105-
106- for ( var i = 0 ; i < list . Count ; i ++ )
107- {
108- var item = ( Handler ) list [ i ] ;
109- if ( item . hash != hash )
110- {
111- continue ;
112- }
113- args [ 0 ] = item . del ;
114- try
115- {
116- mi . Invoke ( obj , BindingFlags . Default , null , args , null ) ;
117- }
118- catch
119- {
120- continue ;
121- }
122- list . RemoveAt ( i ) ;
123- return true ;
124- }
125-
126- Exceptions . SetError ( Exceptions . ValueError , "unknown event handler" ) ;
127- return false ;
128- }
129-
130-
13124 /// <summary>
13225 /// Descriptor __get__ implementation. A getattr on an event returns
13326 /// a "bound" event that keeps a reference to the object instance.
@@ -141,25 +34,17 @@ public static NewReference tp_descr_get(BorrowedReference ds, BorrowedReference
14134 return Exceptions . RaiseTypeError ( "invalid argument" ) ;
14235 }
14336
144- // If the event is accessed through its type (rather than via
145- // an instance) we return an 'unbound' EventBinding that will
146- // be cached for future accesses through the type.
147-
14837 if ( ob == null )
14938 {
150- if ( self . unbound == null )
151- {
152- self . unbound = new EventBinding ( self , target : null ) . Alloc ( ) . MoveToPyObject ( ) ;
153- }
154- return new NewReference ( self . unbound ) ;
39+ return new NewReference ( ds ) ;
15540 }
15641
15742 if ( Runtime . PyObject_IsInstance ( ob , tp ) < 1 )
15843 {
15944 return Exceptions . RaiseTypeError ( "invalid argument" ) ;
16045 }
16146
162- return new EventBinding ( self , new PyObject ( ob ) ) . Alloc ( ) ;
47+ return new EventBinding ( self . name , self . reg , new PyObject ( ob ) ) . Alloc ( ) ;
16348 }
16449
16550
@@ -192,13 +77,6 @@ public static NewReference tp_repr(BorrowedReference ob)
19277 var self = ( EventObject ) GetManagedObject ( ob ) ! ;
19378 return Runtime . PyString_FromString ( $ "<event '{ self . name } '>") ;
19479 }
195-
196-
197- protected override void Clear ( BorrowedReference ob )
198- {
199- this . unbound = null ! ;
200- base . Clear ( ob ) ;
201- }
20280 }
20381
20482
0 commit comments