Я знаю, что подобные вещи существуют в WPF и формируют приложения с помощью метода Control.Invoke, я также знаю о существовании BackgroundWorker, ThreadPool и т. Д.
Однако я не хочу зависеть от Forms / WPF и хочу убедиться, что работа выполняется последовательно и в одном потоке.
Редактировать: Обоснование: я хочу управлять конечным автоматом из одного потока. События приходят из других жестких тем. Там нет пользовательского интерфейса.
Пока я не мог понять, как это сделать с существующими классами фреймворка, но я мог неправильно понять документацию.
Редактировать: я забыл упомянуть, что я связан с .NET Framework 3.5
То, что я написал до сих пор:
public class Dispatcher
{
string Name;
Thread WorkerThread;
Queue<Action> WorkQueue;
List<Exception> Exceptions;
ManualResetEvent Gate;
volatile bool KeepRunning;
readonly object WorkLocker;
public override string ToString()
{
return String.Format("{0}({1})", this.GetType().Name, Name);
}
public Dispatcher(string name)
{
Name = name;
WorkLocker = new Object();
Gate = new ManualResetEvent(false);
WorkQueue = new Queue<Action>();
Exceptions = new List<Exception>();
}
public void Start()
{
if (WorkerThread == null)
{
WorkerThread = new Thread(doDispatch)
{
IsBackground = true,
Name = this.Name
};
WorkerThread.Start();
}
}
public void Stop()
{
if (WorkerThread != null && WorkerThread.IsAlive)
{
Dispatch(() => { KeepRunning = false; });
WorkerThread.Join();
}
WorkerThread = null;
}
public void Reset()
{
Stop();
lock (WorkLocker)
{
WorkQueue = new Queue<Action>();
Exceptions = new List<Exception>();
}
}
public void Dispatch(Action a)
{
lock (WorkLocker)
{
WorkQueue.Enqueue(a);
}
Gate.Set();
}
public List<Exception> CollectExceptions()
{
List<Exception> result = new List<Exception>();
lock(WorkLocker)
{
foreach(Exception e in Exceptions)
{
result.Add(e);
}
Exceptions.Clear();
}
return result;
}
private void doDispatch()
{
KeepRunning = true;
while (KeepRunning)
{
Gate.WaitOne();
lock (WorkLocker)
{
while (WorkQueue.Count > 0)
{
try
{
WorkQueue.Dequeue()?.Invoke();
}
catch (Exception e)
{
Exceptions.Add(e);
}
}
}
}
}
}
Есть ли способ сделать что-то подобное более простым способом? Еще одна полезная функция - возможность отправлять вызовы с несколькими аргументами.