88namespace Microsoft . ClearScript
99{
1010 /// <summary>
11- /// Represents a host event source.
11+ /// Provides the base implementation for a host event source.
1212 /// </summary>
13- /// <typeparam name="T">The event handler delegate type.</typeparam>
14- public class EventSource < T >
13+ public abstract class EventSource
1514 {
16- private readonly ScriptEngine engine ;
17-
1815 internal EventSource ( ScriptEngine engine , object source , EventInfo eventInfo )
1916 {
2017 MiscHelpers . VerifyNonNullArgument ( engine , nameof ( engine ) ) ;
2118 MiscHelpers . VerifyNonNullArgument ( eventInfo , nameof ( eventInfo ) ) ;
2219
23- if ( eventInfo . EventHandlerType != typeof ( T ) )
24- {
25- throw new ArgumentException ( "Invalid event type" , nameof ( eventInfo ) ) ;
26- }
27-
28- this . engine = engine ;
20+ Engine = engine ;
2921 Source = source ;
3022 EventInfo = eventInfo ;
3123 }
3224
25+ internal ScriptEngine Engine { get ; }
26+
27+ internal abstract Type HandlerType { get ; }
28+
3329 internal object Source { get ; }
3430
3531 internal EventInfo EventInfo { get ; }
@@ -42,33 +38,68 @@ internal EventSource(ScriptEngine engine, object source, EventInfo eventInfo)
4238 /// Connects the host event source to the specified script handler function.
4339 /// </summary>
4440 /// <param name="scriptFunc">The script function that will handle the event.</param>
45- /// <returns>An <see cref="EventConnection{T} "/> that represents the connection.</returns>
46- public EventConnection < T > connect ( object scriptFunc )
41+ /// <returns>An <see cref="EventConnection"/> that represents the connection.</returns>
42+ public EventConnection connect ( object scriptFunc )
4743 {
4844 MiscHelpers . VerifyNonNullArgument ( scriptFunc , nameof ( scriptFunc ) ) ;
49- return engine . CreateEventConnection < T > ( Source , EventInfo , DelegateFactory . CreateDelegate ( engine , scriptFunc , typeof ( T ) ) ) ;
45+ return Engine . CreateEventConnection ( HandlerType , Source , EventInfo , DelegateFactory . CreateDelegate ( Engine , scriptFunc , HandlerType ) ) ;
5046 }
5147
5248 // ReSharper restore InconsistentNaming
5349
5450 #endregion
5551 }
5652
57- internal interface IEventConnection
53+ /// <summary>
54+ /// Represents a host event source.
55+ /// </summary>
56+ /// <typeparam name="T">The event handler delegate type.</typeparam>
57+ public sealed class EventSource < T > : EventSource
5858 {
59- void Break ( ) ;
59+ internal EventSource ( ScriptEngine engine , object source , EventInfo eventInfo )
60+ : base ( engine , source , eventInfo )
61+ {
62+ if ( eventInfo . EventHandlerType != typeof ( T ) )
63+ {
64+ throw new ArgumentException ( "Invalid event type (handler type mismatch)" , nameof ( eventInfo ) ) ;
65+ }
66+ }
67+
68+ #region EventSource overrides
69+
70+ internal override Type HandlerType => typeof ( T ) ;
71+
72+ #endregion
73+
74+ #region script-callable interface
75+
76+ // ReSharper disable InconsistentNaming
77+
78+ /// <summary>
79+ /// Connects the host event source to the specified script handler function.
80+ /// </summary>
81+ /// <param name="scriptFunc">The script function that will handle the event.</param>
82+ /// <returns>An <see cref="EventConnection{T}"/> that represents the connection.</returns>
83+ public new EventConnection < T > connect ( object scriptFunc )
84+ {
85+ MiscHelpers . VerifyNonNullArgument ( scriptFunc , nameof ( scriptFunc ) ) ;
86+ return Engine . CreateEventConnection < T > ( Source , EventInfo , DelegateFactory . CreateDelegate ( Engine , scriptFunc , typeof ( T ) ) ) ;
87+ }
88+
89+ // ReSharper restore InconsistentNaming
90+
91+ #endregion
6092 }
6193
6294 /// <summary>
63- /// Represents a connection between a host event source and a script handler function.
95+ /// Provides the base implementation for a connection between a host event source and a script handler function.
6496 /// </summary>
65- /// <typeparam name="T">The event handler delegate type.</typeparam>
66- public class EventConnection < T > : IEventConnection
97+ public abstract class EventConnection
6798 {
6899 private readonly ScriptEngine engine ;
69100 private readonly object source ;
70- private readonly EventInfo eventInfo ;
71- private readonly Delegate handler ;
101+ private readonly MethodInfo removeMethod ;
102+ private readonly object [ ] parameters ;
72103 private readonly InterlockedOneWayFlag brokenFlag = new InterlockedOneWayFlag ( ) ;
73104
74105 internal EventConnection ( ScriptEngine engine , object source , EventInfo eventInfo , Delegate handler )
@@ -77,17 +108,28 @@ internal EventConnection(ScriptEngine engine, object source, EventInfo eventInfo
77108 MiscHelpers . VerifyNonNullArgument ( handler , nameof ( handler ) ) ;
78109 MiscHelpers . VerifyNonNullArgument ( eventInfo , nameof ( eventInfo ) ) ;
79110
80- if ( eventInfo . EventHandlerType != typeof ( T ) )
111+ if ( ! MiscHelpers . Try ( out var addMethod , ( ) => eventInfo . GetAddMethod ( true ) ) || ( addMethod == null ) )
81112 {
82- throw new ArgumentException ( "Invalid event type" , nameof ( eventInfo ) ) ;
113+ throw new ArgumentException ( "Invalid event type (no accessible add method)" , nameof ( eventInfo ) ) ;
114+ }
115+
116+ if ( ! MiscHelpers . Try ( out removeMethod , ( ) => eventInfo . GetRemoveMethod ( true ) ) || ( removeMethod == null ) )
117+ {
118+ throw new ArgumentException ( "Invalid event type (no accessible remove method)" , nameof ( eventInfo ) ) ;
83119 }
84120
85121 this . engine = engine ;
86122 this . source = source ;
87- this . eventInfo = eventInfo ;
88- this . handler = handler ;
89123
90- eventInfo . AddEventHandler ( source , handler ) ;
124+ addMethod . Invoke ( source , parameters = new object [ ] { handler } ) ;
125+ }
126+
127+ internal void Break ( )
128+ {
129+ if ( brokenFlag . Set ( ) )
130+ {
131+ removeMethod . Invoke ( source , parameters ) ;
132+ }
91133 }
92134
93135 #region script-callable interface
@@ -105,17 +147,21 @@ public void disconnect()
105147 // ReSharper restore InconsistentNaming
106148
107149 #endregion
150+ }
108151
109- #region IEventConnection implementation
110-
111- void IEventConnection . Break ( )
152+ /// <summary>
153+ /// Represents a connection between a host event source and a script handler function.
154+ /// </summary>
155+ /// <typeparam name="T">The event handler delegate type.</typeparam>
156+ public sealed class EventConnection < T > : EventConnection
157+ {
158+ internal EventConnection ( ScriptEngine engine , object source , EventInfo eventInfo , Delegate handler )
159+ : base ( engine , source , eventInfo , handler )
112160 {
113- if ( brokenFlag . Set ( ) )
161+ if ( eventInfo . EventHandlerType != typeof ( T ) )
114162 {
115- eventInfo . RemoveEventHandler ( source , handler ) ;
163+ throw new ArgumentException ( "Invalid event type ( handler type mismatch)" , nameof ( eventInfo ) ) ;
116164 }
117165 }
118-
119- #endregion
120166 }
121167}
0 commit comments