如何创建和执行一个Action>

本文关键字:Action 一个 Task bool 执行 何创建 创建 | 更新日期: 2023-09-27 17:49:21

我希望创建一个异步回调机制,感兴趣的各方可以注册一个或多个回调方法。

我想触发队列中所有Actions的和await完成,并确定它们中是否有任何一个返回true

有没有人对现有的库或模式有什么建议来实现这一点?

如何创建和执行一个Action<Task<bool>>

我想触发并等待队列中所有动作的完成,并确定其中是否有一个返回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;
    }
}

我认为代码是不言自明的。