如何创建和执行一个Action>
本文关键字:Action 一个 Task bool 执行 何创建 创建 | 更新日期: 2023-09-27 17:49:21
我希望创建一个异步回调机制,感兴趣的各方可以注册一个或多个回调方法。
我想触发队列中所有Actions
的和await
完成,并确定它们中是否有任何一个返回true
。
我想触发并等待队列中所有动作的完成,并确定其中是否有一个返回true。
如果您想同时调用它们并等待它们全部完成,那么可以这样做:
IEnumerable<Func<Task<bool>>> queue = ...;
var results = await Task.WhenAll(queue.Select(x => x()));
return results.Any(x => x);
如果你想一次调用一个,那么可以这样做:
IEnumerable<Func<Task<bool>>> queue = ...;
foreach (var callback in queue)
{
if (await callback())
return true;
}
return false;
由于我不是很确定,您打算在哪里等待异步调用完成,我摆弄了一下,并为您提供了一个双向解决方案。
这个解决方案提供了两种方法来获得关于方法完成的通知…
- …通过
Event
,当任何方法完成时触发(在EventArgs中提供MethodInfo和Result) - …通过
MethodInvokeState
中的阻塞getter
所以要实现它,你需要MethodCompletedEventArgs
:
public class MethodCompletedEventArgs : EventArgs
{
private MethodInfo m_method;
private Boolean m_result;
public MethodCompletedEventArgs(MethodInfo mi, Boolean result)
{
m_method = mi;
m_result = result;
}
public MethodInfo Method { get { return m_method; } }
public Boolean Result { get { return m_result; } }
}
和
的对象- 保存目标委托
- 返回结果(阻塞)
- 封装调用(提供结果)
MethodInvokeState
:
public class MethodInvokeState
{
public MethodInvokeState(Func<bool> target)
{
m_target = target;
m_mreCompleted = new ManualResetEvent(false);
m_blnCompleted = false;
}
private Func<bool> m_target;
private ManualResetEvent m_mreCompleted;
private Boolean m_blnCompleted;
private Boolean m_result;
public Boolean WaitForCompletion()
{
if (!m_blnCompleted)
m_mreCompleted.WaitOne();
return m_result;
}
public Boolean Invoke()
{
m_result = m_target.Invoke();
m_blnCompleted = true;
m_mreCompleted.Set();
return m_result;
}
public MethodInfo Method { get { return m_target.Method; } }
}
最后需要Scheduler,它具有以下属性:
- 可以注册
MethodInvokeState
对象(排队) - 它可以被启动(这样它就可以取消方法队列并调用它们)
- 它可以被停止(中止调用进程)
- 它提供了一个
MethodCompleted
事件(使用上述EventArgs)
这里的MethodScheduler
:
public class MethodScheduler
{
public MethodScheduler()
{
m_qAction = new Queue<MethodInvokeState>();
m_mreNewAction = new ManualResetEvent(false);
m_objQueueLock = new Object();
m_blnClosing = false;
}
private Queue<MethodInvokeState> m_qAction;
private ManualResetEvent m_mreNewAction;
private Object m_objQueueLock;
private Thread m_trdInvoker;
private Boolean m_blnInvoking;
private Boolean m_blnClosing;
public delegate void MethodCompletedEventHandler(Object sender, MethodCompletedEventArgs e);
public event MethodCompletedEventHandler MethodCompleted;
public void Init()
{
m_trdInvoker = new Thread(new ThreadStart(__invoker));
m_blnInvoking = true;
m_trdInvoker.Start();
}
private void __invoker()
{
while (m_blnInvoking)
{
int count = 0;
lock (m_objQueueLock)
{
if((count = m_qAction.Count) == 0)
{
m_mreNewAction.Reset();
}
}
if (count == 0) m_mreNewAction.WaitOne();
if (!m_blnClosing)
{
MethodInvokeState p = m_qAction.Dequeue();
bool result = p.Invoke();
if (MethodCompleted != null)
MethodCompleted(p, new MethodCompletedEventArgs(p.Method, result));
}
}
}
public void Stop()
{
m_blnInvoking = false;
m_blnClosing = true;
m_mreNewAction.Set();
}
public void RegisterMethod(MethodInvokeState p) {
if (!m_blnInvoking) throw new InvalidOperationException("Cannot register a method if invoker is not initialized");
Console.WriteLine(" * MethodScheduler: Registering Method: " + p.Method.Name);
lock (m_objQueueLock)
{
m_qAction.Enqueue(p);
m_mreNewAction.Set();
}
}
}
最后这里有一个如何使用它的例子:
class Program
{
static void Main(string[] args)
{
MethodScheduler ms = new MethodScheduler();
ms.Init();
ms.MethodCompleted += MethodCompletedHandler;
MethodInvokeState mtA = new MethodInvokeState(new Func<bool>(SomeMethodA));
MethodInvokeState mtB = new MethodInvokeState(new Func<bool>(SomeMethodB));
ms.RegisterMethod(mtA);
ms.RegisterMethod(mtB);
Console.WriteLine(" * SENDER: Waiting for completion (SomeMethodA) ...");
bool result = mtA.WaitForCompletion();
Console.WriteLine(" * SENDER: SomeMethodA completed: " + result);
Console.WriteLine(" * SENDER: Waiting for completion (SomeMethodB) ...");
result = mtB.WaitForCompletion();
Console.WriteLine(" * SENDER: SomeMethodB completed: " + result);
Console.WriteLine("Press any key to exit ...");
Console.ReadKey();
ms.Stop();
}
public static void MethodCompletedHandler(Object sender, MethodCompletedEventArgs e)
{
Console.WriteLine(" * HANDLER: Method '{0}' completed with: {1} " , e.Method.Name, e.Result.ToString());
}
public static bool SomeMethodA()
{
Console.WriteLine(" * SomeMethodA: will succeed in 5 seconds!");
Thread.Sleep(5000);
return true;
}
public static bool SomeMethodB()
{
Console.WriteLine(" * SomeMethodB: will fail in 3 seconds!");
Thread.Sleep(3000);
return false;
}
}
我认为代码是不言自明的。