在单一方法调用中包装方法和事件处理程序

问题描述:

这可能是一个非常愚蠢的问题,特别是来自在.Net工作了几年的人。这个问题很简单:在单一方法调用中包装方法和事件处理程序

有没有办法来包装方法调用+的事件处理程序中,根据我的理解一个方法调用

创建从方法 ,它不是。这里有一个例子:

// Starts the long running transaction, when this method completes 
// we have no idea whether the transaction actually succeeded/failed 
// /finished/etc 
public bool BeginLongRunningTransaction(/*args*/) 
{ 
    myService.LongRunningTransactionComplete += TransactionComplete; 

    // Runs the actual transaction - this can take some time 
    myService.ExecuteLongRunningTransaction(); 
    return true; 
} 

// Handles the long running transaction complete event 
// which allows us to see if the transaction suceeded/failed/etc 
private void TransactionComplete(/*args*/) 
{ 
    /* Stuff complete! */ 
} 

会发生什么事,是一个呼叫者将调用BeginLongRunningTransaction()方法,将开始长期运行的事务,但将无法返回该交易的结果,因为这结果将在TransactionComplete()事件处理程序中返回。什么我想看到的是是否有一种方式来开始和返回BeginLongRunningTransaction()方法中的长期运行的事务的结果,所以对主叫

我知道同步等待模式并且还知道内联事件处理程序。根据我的理解,这些都不能达到我想要的。

这个问题的主要原因是从订阅客户的角度简化了通信。

非常感谢!

+0

什么是为myService?它是一个Web服务?你使用的是什么版本的Visual Studio? – NineBerry

+2

_“对DoStuff()的请求和实际的DoStuff()功能将在不同的线程上完成”_ - 说谁?在你的问题中根本没有任何建议涉及多个线程。在C#中使用'event'肯定不是隐含的,也不是通常的方法调用。你的问题太模糊不清。修正你的问题,使其包含一个很好的[mcve],清楚地显示你已经尝试了什么,并且解释_precisely_代码的作用以及你希望它做什么。 –

+0

道歉不清楚。我尽量保持示例尽可能简单。我已经用更好的命名+评论更新了这个问题,希望更清楚地说明问题。 – Ross

你的意思是这样吗?

public bool DoStuff(/*args*/) 
{ 
    myService.StuffComplete += (/*args*/) => { /* Stuff complete! */ }; 
    myService.DoStuff(); 
    return true; 
} 

但是,如果你的意思是你想从public bool DoStuff(/*args*/)的返回值是事情发生在/* Stuff complete! */而不是结果的硬编码true那么你需要更聪明一点。

你可以做这样的事情:

public bool DoStuff(/*args*/) 
{ 
    bool result = false; 
    myService.StuffComplete += (/*args*/) => 
    { 
     result = myService.Status; 
    }; 
    myService.DoStuff(); 
    return result; 
} 

下面这段代码期望呼叫纯粹运行在当前线程上。如果myService.DoStuff()启动一个新线程,则myService.StuffComplete处理程序将在public bool DoStuff(/*args*/)完成后运行,并且不会得到您期望的结果。

如果您认为myService确实在幕后调用了新线程(或者您希望代码在后台任务上运行),那么您应该考虑使用微软的Reactive Framework。然后,你可以这样做:

public IObservable<bool> DoStuff(/*args*/) 
{ 
    return Observable.Create<bool>(o => 
    { 
     var subscription = 
      Observable 
       .FromEventPattern<EventHandler, EventArgs>(
        h => myService.StuffComplete += h, 
        h => myService.StuffComplete -= h) 
       .Select(x => myService.Status) 
       .Take(1) 
       .Subscribe(o); 
     myService.DoStuff(); 
     return subscription; 
    }); 
} 

这改变了方法的输出从boolIObservable<bool>,这意味着你可以观察的结果时,它已准备就绪。

DoStuff().Subscribe(result => { /* handle result */ }; 
+1

非常感谢你的回答!我现在觉得自己很愚蠢,因为没有想到自己,特别是我之前看过内联事件处理程序。我认为我弄糊涂的部分是线程 - 我认为长时间运行的事务(DoStuff())将在不同的线程上执行,而不是必须的。我也不知道Reactive框架,但是当DoStuff()确实发生在另一个线程上时,它看起来非常有用。 – Ross

尝试使用async-await。

小的代码示例(我没有测试):

class YourClass 
{ 
    public async Task<bool> DoStuff(/*args*/) 
    { 
     var handler = new StuffCompleteHandler(myService); 
     await handler.GetTask(); 
     return true; 
    } 

    private class StuffCompleteHandler 
    { 
     private ???? myService; 
     private TaskCompletionSource<bool> taskSource = new TaskCompletionSource<bool>(); 

     public StuffCompleteHandler(???? myService) 
     { 
      this.myService = myService; 
      this.myService.StuffComplete += this.StuffComplete; 
     } 

     private void StuffComplete(/*args*/) 
     { 
      this.myService.StuffComplete -= this.StuffComplete; 
      try 
      { 
       /* Stuff complete! */ 
       // do some thing 
       this.taskSource.SetResult(true); 
      } 
      catch (Exception e) 
      { 
       this.taskSource.SetException(e); 
      } 
     } 

     public Task GetTask() => this.taskSource.Task; 
    } 
} 
+0

感谢您的回复:)我认为这并不能让我获得我期待的结果,但它仍然是一个值得考虑的有趣模式。 – Ross