mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
Improve InvokeOnMainThread mechanism
Add documentation to make the invoke mechanism easier to understand Make it clear in documentation that code is invoked synchronously Use Action and Func<T> for minimizing the amount of code to write Use type parameter T to automatically adjust return value type Throw exceptions on the calling thread, not the main thread
This commit is contained in:
parent
9e5364a4ff
commit
c1cfaf520d
6 changed files with 164 additions and 59 deletions
|
|
@ -6,42 +6,121 @@ using System.Threading;
|
|||
|
||||
namespace MinecraftClient
|
||||
{
|
||||
public class TaskWithResult
|
||||
/// <summary>
|
||||
/// Holds an asynchronous task with return value
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the return value</typeparam>
|
||||
public class TaskWithResult<T>
|
||||
{
|
||||
private Delegate Task;
|
||||
private AutoResetEvent ResultEvent = new AutoResetEvent(false);
|
||||
private AutoResetEvent resultEvent = new AutoResetEvent(false);
|
||||
private Func<T> task;
|
||||
private T result = default(T);
|
||||
private Exception exception = null;
|
||||
private bool taskRun = false;
|
||||
private object taskRunLock = new object();
|
||||
|
||||
public object Result;
|
||||
|
||||
public TaskWithResult(Delegate task)
|
||||
/// <summary>
|
||||
/// Create a new asynchronous task with return value
|
||||
/// </summary>
|
||||
/// <param name="task">Delegate with return value</param>
|
||||
public TaskWithResult(Func<T> task)
|
||||
{
|
||||
Task = task;
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute the delegate and set the <see cref="Result"/> property to the returned value
|
||||
/// Check whether the task has finished running
|
||||
/// </summary>
|
||||
/// <returns>Value returned from delegate</returns>
|
||||
public object Execute()
|
||||
public bool HasRun
|
||||
{
|
||||
Result = Task.DynamicInvoke();
|
||||
return Result;
|
||||
get
|
||||
{
|
||||
return taskRun;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Block the program execution
|
||||
/// Get the task result (return value of the inner delegate)
|
||||
/// </summary>
|
||||
public void Block()
|
||||
/// <exception cref="System.InvalidOperationException">Thrown if the task is not finished yet</exception>
|
||||
public T Result
|
||||
{
|
||||
ResultEvent.WaitOne();
|
||||
get
|
||||
{
|
||||
if (taskRun)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else throw new InvalidOperationException("Attempting to retrieve the result of an unfinished task");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resume the program execution
|
||||
/// Get the exception thrown by the inner delegate, if any
|
||||
/// </summary>
|
||||
public void Release()
|
||||
public Exception Exception
|
||||
{
|
||||
ResultEvent.Set();
|
||||
get
|
||||
{
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute the task in the current thread and set the <see cref="Result"/> property or <see cref=""/>to the returned value
|
||||
/// </summary>
|
||||
public void ExecuteSynchronously()
|
||||
{
|
||||
// Make sur the task will not run twice
|
||||
lock (taskRunLock)
|
||||
{
|
||||
if (taskRun)
|
||||
{
|
||||
throw new InvalidOperationException("Attempting to run a task twice");
|
||||
}
|
||||
}
|
||||
|
||||
// Run the task
|
||||
try
|
||||
{
|
||||
result = task();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
exception = e;
|
||||
}
|
||||
|
||||
// Mark task as complete and release wait event
|
||||
lock (taskRunLock)
|
||||
{
|
||||
taskRun = true;
|
||||
}
|
||||
resultEvent.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wait until the task has run from another thread and get the returned value or exception thrown by the task
|
||||
/// </summary>
|
||||
/// <returns>Task result once available</returns>
|
||||
/// <exception cref="System.Exception">Any exception thrown by the task</exception>
|
||||
public T WaitGetResult()
|
||||
{
|
||||
// Wait only if the result is not available yet
|
||||
bool mustWait = false;
|
||||
lock (taskRunLock)
|
||||
{
|
||||
mustWait = !taskRun;
|
||||
}
|
||||
if (mustWait)
|
||||
{
|
||||
resultEvent.WaitOne();
|
||||
}
|
||||
|
||||
// Receive exception from task
|
||||
if (exception != null)
|
||||
throw exception;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue