using System; using System.Threading; namespace Plugin { /// /// Result of a query to the engine. Allows to wait until the result is available. /// /// Type of data inside the result. public interface IQueryResult { /// /// Waits for the result, returns true if the timeout didn't expire. /// bool Join(out T result, int millisecondsTimeout = QueryResult.DefaultTimeout); /// /// Triggered when the query is filled. /// event Action Done; } /// /// Result of a query to the engine. Allows to wait until the result is available. /// /// Type of data inside the result. public class QueryResult : IQueryResult { public const int DefaultTimeout = 2500; private readonly AbstractPlugin _plugin; private readonly ManualResetEvent _waitHandle = new ManualResetEvent(false); private T _content; public QueryResult(AbstractPlugin plugin) { _plugin = plugin; } public T Content { get { return _content; } set { _content = value; _waitHandle.Set(); OnDone(); } } public bool Join(out T result, int millisecondsTimeout = DefaultTimeout) { if (_waitHandle.WaitOne(millisecondsTimeout)) { result = _content; return true; } result = _content; _plugin.ReportTimeoutFailure(); return false; } /// /// Separated in a backend and the interface so we can trigger the event right away if already filled. /// private event Action DoneBackend; /// /// Triggered when the query is filled. /// public event Action Done { add { DoneBackend += value; // When already set, we trigger the event right now. if (_waitHandle.WaitOne(0)) { OnDone(); } } remove { DoneBackend -= value; } } protected virtual void OnDone() { var done = DoneBackend; if (done != null) { done(Content); } } } }