Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用任务<;T>;引发事件并等待事件完成_C#_Multithreading_Asynchronous_Event Handling_Task Parallel Library - Fatal编程技术网

C# 如何使用任务<;T>;引发事件并等待事件完成

C# 如何使用任务<;T>;引发事件并等待事件完成,c#,multithreading,asynchronous,event-handling,task-parallel-library,C#,Multithreading,Asynchronous,Event Handling,Task Parallel Library,我有以下情况: 请求启动Web服务的客户端 public bool Start(MyProject project, string error) 在方法中从客户端接收调用的web服务 public event EventHandler<StartEventArgs> startEvent; public bool Start(MyProject project, string error) { Task<bool> result = StartAsync(p

我有以下情况:

  • 请求启动Web服务的客户端

    public bool Start(MyProject project, string error)
    
  • 在方法中从客户端接收调用的web服务

    public event EventHandler<StartEventArgs> startEvent;
    
    public bool Start(MyProject project, string error)
    {
        Task<bool> result = StartAsync(project, error);
    
        return result.Result;
    }
    
    protected virtual void OnStart(StartEventArgs e)
    {
        // thread safe trick, snapshot of event
        var se = startEvent;
        if (se != null)
        {
            startEvent(this, e);
        }
    }
    
    private Task<bool> StartAsync(MyProject project, string error)
    {
        var taskCompletion = new TaskCompletionSource<bool>();
    
        this.startEvent += (p, e) => taskCompletion.TrySetResult((e.Error == string.Empty) ? true : false);
    
        this.OnStart(new StartEventArgs(project, error));
    
        return taskCompletion.Task;
    }
    
  • 我希望web服务在任务中触发事件,然后等待app.exe中的函数完成,然后返回此处通知用户任务已成功完成

  • 我不知道如何做到这一点,但在理论上,它看起来是这样的:

    Task<bool> startTask = Task.Factory.StartNew(() => { OnStart() });
    startTask.WaitAll(); // I think this is what I would need to for 4.0
    return startTask.Result
    
    Task startTask=Task.Factory.StartNew(()=>{OnStart()});
    startTask.WaitAll();//我想这就是我需要为4.0做的
    返回startTask.Result
    
    我希望我的描述足够让人明白我在做什么。我希望服务不必了解客户机的任何信息,只需运行任务,一旦事件完成执行,返回到此点并向客户机返回表示成功/失败的布尔值

    这是可能的还是我采取了一种非常错误的方法

    更新:
    很明显,OnStart不是一个事件,因此我如何做您试图向我解释的事情?

    您可以通过将描述基于事件的异步模式的事件包装到
    任务中。基本模式通常类似于:

    Task<bool> StartAsync()
    {
        var tcs = new TaskCompletionSource<bool>();
    
        // When the event returns, set the result, which "completes" the task
        service.OnStarted += (o,e) => tcs.TrySetResult(e.Success);
    
        // If an error occurs, error out the task (optional)
        service.OnStartError += (o,e) => tcs.TrySetException(e.Exception);
    
        // Start the service call
        service.Start();
    
        // Return the Task<T>
        return tcs.Task;
    }
    
    Task StartAsync()
    {
    var tcs=new TaskCompletionSource();
    //当事件返回时,设置“完成”任务的结果
    service.onstart+=(o,e)=>tcs.TrySetResult(e.Success);
    //如果发生错误,请将任务出错(可选)
    service.OnStartError+=(o,e)=>tcs.TrySetException(e.Exception);
    //启动服务呼叫
    service.Start();
    //返回任务
    返回tcs.Task;
    }
    
    所以我想我现在明白了这需要怎么做,我现在就是这么做的

    服务代码:

    public void SetStartTask(Task<bool> startTask)
            {
                this.startTask = startTask;
            }
    
    public bool Start(RtProjectInfo project, string error)
            {
                StartEventArgs args = new StartEventArgs(project, error);
    
                OnStart(args);
    
                return startTask.Result;
            }
    
    protected virtual void OnStart(StartEventArgs e)
            {
                // thread safe trick, snapshot of event
                var se = startEvent;
    
                if (se != null)
                {
                    startEvent(this, e);
                }
            }
    
    public void StartFinished(MyProject project, string error)
            {
                OnStartFinish(new StartEventArgs(project, error));
            }
    
    protected virtual void OnStartFinish(StartEventArgs e)
                {
                    var sef = startFinished;
    
                    if (sef != null)
                    {
                        startFinished(this, e);
                    }
                }
    
    public void设置开始任务(任务开始任务)
    {
    this.startTask=startTask;
    }
    公共bool启动(RtProjectInfo项目,字符串错误)
    {
    StartEventArgs args=新的StartEventArgs(项目,错误);
    OnStart(args);
    返回startTask.Result;
    }
    受保护的虚拟void OnStart(StartEventArgs e)
    {
    //线程安全技巧,事件快照
    var se=起始事件;
    如果(se!=null)
    {
    startEvent(本,e);
    }
    }
    public void StartFinished(MyProject,字符串错误)
    {
    OnStartFinish(新的StartEventArgs(项目,错误));
    }
    开始完成时受保护的虚拟空间(StartEventArgs e)
    {
    var sef=启动完成;
    如果(sef!=null)
    {
    开始完成(本,e);
    }
    }
    
    下面是一个测试客户机实现

    public void Start_Event(object sender, StartEventArgs e)
            {
                Task<bool> startTask = StartAsync();
    
                service.SetStartTask(startTask);
    
                DoOtherWork();
                DoOtherWork();
                DoOtherWork();
            }
    
    private Task<bool> StartAsync()
            {
                var taskCompletion = new TaskCompletionSource<bool>();
    
                service.startFinished += (p, e) => 
                {
                    taskCompletion.TrySetResult((e.Error == string.Empty) ? true : false); 
                };
    
                return taskCompletion.Task;
            }
    
    private void DoingWork()
            {
                for(int i = 0; i < 100; ++i)
                {
    
                }
    
                service.StartFinished(project, error);
            }
    
            private void DoOtherWork()
            {
                for (int i = 0; i < 100000; ++i)
                {                    
                }
            }
    
    public void Start\u事件(对象发送方,StartEventArgs e)
    {
    任务startTask=StartAsync();
    service.SetStartTask(startTask);
    DoOtherWork();
    DoOtherWork();
    DoOtherWork();
    }
    专用任务StartAsync()
    {
    var taskCompletion=new TaskCompletionSource();
    service.startFinished+=(p,e)=>
    {
    taskCompletion.TrySetResult((e.Error==string.Empty)?true:false;
    };
    返回taskCompletion.Task;
    }
    私人工作
    {
    对于(int i=0;i<100;++i)
    {
    }
    服务。启动完成(项目,错误);
    }
    私人物品
    {
    对于(int i=0;i<100000;++i)
    {                    
    }
    }
    

    所以很明显,每当有人客户端调用DoingWork()时,就会收到该事件,并且每个人都很高兴!如果有人有更好的建议,请提供给我,因为我正在学习如何正确使用TPL。

    上面的代码是否在App.exe端用于此场景?不管怎样,我刚刚意识到(或者我想我是这样做的)应该在哪里:)我将编辑我的代码,以便您可以看到我正在尝试做什么,对于如何使用TaskCompletionSource,我仍然有点困惑。这取决于具体情况,但在实现此模式时,在任务完成后删除处理程序非常重要。至少,如果事件曾多次触发,或者触发事件的对象将比此方法长一段时间。@Servy如何在这样的模式中删除处理程序?
    public void Start_Event(object sender, StartEventArgs e)
            {
                Task<bool> startTask = StartAsync();
    
                service.SetStartTask(startTask);
    
                DoOtherWork();
                DoOtherWork();
                DoOtherWork();
            }
    
    private Task<bool> StartAsync()
            {
                var taskCompletion = new TaskCompletionSource<bool>();
    
                service.startFinished += (p, e) => 
                {
                    taskCompletion.TrySetResult((e.Error == string.Empty) ? true : false); 
                };
    
                return taskCompletion.Task;
            }
    
    private void DoingWork()
            {
                for(int i = 0; i < 100; ++i)
                {
    
                }
    
                service.StartFinished(project, error);
            }
    
            private void DoOtherWork()
            {
                for (int i = 0; i < 100000; ++i)
                {                    
                }
            }