-
Notifications
You must be signed in to change notification settings - Fork 160
Expand file tree
/
Copy pathHostEvent.cs
More file actions
167 lines (133 loc) · 5.75 KB
/
HostEvent.cs
File metadata and controls
167 lines (133 loc) · 5.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
using System;
using System.Reflection;
using Microsoft.ClearScript.Util;
namespace Microsoft.ClearScript
{
/// <summary>
/// Provides the base implementation for a host event source.
/// </summary>
public abstract class EventSource
{
internal EventSource(ScriptEngine engine, object source, EventInfo eventInfo)
{
MiscHelpers.VerifyNonNullArgument(engine, nameof(engine));
MiscHelpers.VerifyNonNullArgument(eventInfo, nameof(eventInfo));
Engine = engine;
Source = source;
EventInfo = eventInfo;
}
internal ScriptEngine Engine { get; }
internal abstract Type HandlerType { get; }
internal object Source { get; }
internal EventInfo EventInfo { get; }
#region script-callable interface
// ReSharper disable InconsistentNaming
/// <summary>
/// Connects the host event source to the specified script handler function.
/// </summary>
/// <param name="scriptFunc">The script function that will handle the event.</param>
/// <returns>An <c><see cref="EventConnection"/></c> that represents the connection.</returns>
public EventConnection connect(object scriptFunc)
{
MiscHelpers.VerifyNonNullArgument(scriptFunc, nameof(scriptFunc));
return Engine.CreateEventConnection(HandlerType, Source, EventInfo, DelegateFactory.CreateDelegate(Engine, scriptFunc, HandlerType));
}
// ReSharper restore InconsistentNaming
#endregion
}
/// <summary>
/// Represents a host event source.
/// </summary>
/// <typeparam name="T">The event handler delegate type.</typeparam>
public sealed class EventSource<T> : EventSource
{
internal EventSource(ScriptEngine engine, object source, EventInfo eventInfo)
: base(engine, source, eventInfo)
{
if (eventInfo.EventHandlerType != typeof(T))
{
throw new ArgumentException("Invalid event type (handler type mismatch)", nameof(eventInfo));
}
}
#region EventSource overrides
internal override Type HandlerType => typeof(T);
#endregion
#region script-callable interface
// ReSharper disable InconsistentNaming
/// <summary>
/// Connects the host event source to the specified script handler function.
/// </summary>
/// <param name="scriptFunc">The script function that will handle the event.</param>
/// <returns>An <c><see cref="EventConnection{T}"/></c> that represents the connection.</returns>
public new EventConnection<T> connect(object scriptFunc)
{
MiscHelpers.VerifyNonNullArgument(scriptFunc, nameof(scriptFunc));
return Engine.CreateEventConnection<T>(Source, EventInfo, DelegateFactory.CreateDelegate(Engine, scriptFunc, typeof(T)));
}
// ReSharper restore InconsistentNaming
#endregion
}
/// <summary>
/// Provides the base implementation for a connection between a host event source and a script handler function.
/// </summary>
public abstract class EventConnection
{
private readonly ScriptEngine engine;
private readonly object source;
private readonly MethodInfo removeMethod;
private readonly object[] parameters;
private readonly InterlockedOneWayFlag brokenFlag = new();
internal EventConnection(ScriptEngine engine, object source, EventInfo eventInfo, Delegate handler)
{
MiscHelpers.VerifyNonNullArgument(engine, nameof(engine));
MiscHelpers.VerifyNonNullArgument(handler, nameof(handler));
MiscHelpers.VerifyNonNullArgument(eventInfo, nameof(eventInfo));
if (!MiscHelpers.Try(out var addMethod, static eventInfo => eventInfo.GetAddMethod(true), eventInfo) || (addMethod is null))
{
throw new ArgumentException("Invalid event type (no accessible add method)", nameof(eventInfo));
}
if (!MiscHelpers.Try(out removeMethod, static eventInfo => eventInfo.GetRemoveMethod(true), eventInfo) || (removeMethod is null))
{
throw new ArgumentException("Invalid event type (no accessible remove method)", nameof(eventInfo));
}
this.engine = engine;
this.source = source;
addMethod.Invoke(source, parameters = new object[] { handler });
}
internal void Break()
{
if (brokenFlag.Set())
{
removeMethod.Invoke(source, parameters);
}
}
#region script-callable interface
// ReSharper disable InconsistentNaming
/// <summary>
/// Disconnects the host event source from the script handler function.
/// </summary>
public void disconnect()
{
engine.BreakEventConnection(this);
}
// ReSharper restore InconsistentNaming
#endregion
}
/// <summary>
/// Represents a connection between a host event source and a script handler function.
/// </summary>
/// <typeparam name="T">The event handler delegate type.</typeparam>
public sealed class EventConnection<T> : EventConnection
{
internal EventConnection(ScriptEngine engine, object source, EventInfo eventInfo, Delegate handler)
: base(engine, source, eventInfo, handler)
{
if (eventInfo.EventHandlerType != typeof(T))
{
throw new ArgumentException("Invalid event type (handler type mismatch)", nameof(eventInfo));
}
}
}
}