// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.Reflection; using Microsoft.ClearScript.Util; namespace Microsoft.ClearScript { /// /// Represents a host event source. /// /// The event handler delegate type. public class EventSource { private readonly ScriptEngine engine; internal EventSource(ScriptEngine engine, object source, EventInfo eventInfo) { MiscHelpers.VerifyNonNullArgument(engine, nameof(engine)); MiscHelpers.VerifyNonNullArgument(eventInfo, nameof(eventInfo)); if (eventInfo.EventHandlerType != typeof(T)) { throw new ArgumentException("Invalid event type", nameof(eventInfo)); } this.engine = engine; Source = source; EventInfo = eventInfo; } internal object Source { get; } internal EventInfo EventInfo { get; } #region script-callable interface // ReSharper disable InconsistentNaming /// /// Connects the host event source to the specified script handler function. /// /// The script function that will handle the event. /// An that represents the connection. public EventConnection connect(object scriptFunc) { MiscHelpers.VerifyNonNullArgument(scriptFunc, nameof(scriptFunc)); return engine.CreateEventConnection(Source, EventInfo, DelegateFactory.CreateDelegate(engine, scriptFunc, typeof(T))); } // ReSharper restore InconsistentNaming #endregion } internal interface IEventConnection { void Break(); } /// /// Represents a connection between a host event source and a script handler function. /// /// The event handler delegate type. public class EventConnection : IEventConnection { private readonly ScriptEngine engine; private readonly object source; private readonly EventInfo eventInfo; private readonly Delegate handler; private readonly InterlockedOneWayFlag brokenFlag = new InterlockedOneWayFlag(); 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 (eventInfo.EventHandlerType != typeof(T)) { throw new ArgumentException("Invalid event type", nameof(eventInfo)); } this.engine = engine; this.source = source; this.eventInfo = eventInfo; this.handler = handler; eventInfo.AddEventHandler(source, handler); } #region script-callable interface // ReSharper disable InconsistentNaming /// /// Disconnects the host event source from the script handler function. /// public void disconnect() { engine.BreakEventConnection(this); } // ReSharper restore InconsistentNaming #endregion #region IEventConnection implementation void IEventConnection.Break() { if (brokenFlag.Set()) { eventInfo.RemoveEventHandler(source, handler); } } #endregion } }