C# 包装方法&;单个方法调用中的事件处理程序

C# 包装方法&;单个方法调用中的事件处理程序,c#,.net,C#,.net,这可能是一个非常愚蠢的问题,尤其是来自在.Net工作了几年的人。问题很简单: 有没有一种方法可以将方法调用和事件处理程序(已创建)包装在一起 在单个方法调用中使用该方法 根据我的理解,它不是。下面是一个例子: // Starts the long running transaction, when this method completes // we have no idea whether the transaction actually succeeded/failed // /finis

这可能是一个非常愚蠢的问题,尤其是来自在.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()方法中,是否有一种方法可以开始并返回长时间运行的事务的结果,从而返回给调用方

我知道同步等待模式,也知道内联事件处理程序。据我所知,这两个目标都无法实现我的目标

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

非常感谢

你是说像这样吗

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
确实在幕后调用了新线程(或者您希望在后台任务上运行代码),那么您应该考虑使用Microsoft的反应式框架。然后你可以这样做:

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;
    });
}
尝试使用异步等待

小代码示例(我不是测试):

classyourclass
{
公共异步任务DoStuff(/*args*/)
{
var handler=新的StuffCompleteHandler(myService);
wait handler.GetTask();
返回true;
}
私有类StuffCompleteHandler
{
私人???我的服务;
私有TaskCompletionSource taskSource=新TaskCompletionSource();
public Stuff CompleteHandler(????myService)
{
this.myService=myService;
this.myService.StuffComplete+=this.StuffComplete;
}
私有void填充完成(/*args*/)
{
this.myService.StuffComplete-=this.StuffComplete;
尝试
{
/*东西全齐了*/
//做点什么
this.taskSource.SetResult(true);
}
捕获(例外e)
{
this.taskSource.SetException(e);
}
}
公共任务GetTask()=>this.taskSource.Task;
}
}

什么是myService?是网络服务吗?您使用的是哪个版本的Visual Studio?“对DoStuff()的请求和实际的DoStuff()功能将在不同的线程上完成”——谁说?您的问题中没有任何内容表明涉及多个线程。在C#中使用
事件
时,它当然不是隐式的,通常也不是方法调用。你的问题太模糊和不清楚了。修正你的问题,让它包含一个好的代码,清楚地显示你已经尝试了什么,并准确地解释代码是做什么的,以及你希望它做什么。为没有说得更清楚而道歉。我尽量使这个例子尽可能简单。我已经用更好的命名+评论更新了这个问题,希望能让它更清楚。非常感谢你的出色回答!我现在觉得自己很愚蠢,因为我自己没有弄明白这一点,特别是我以前确实研究过内联事件处理程序。我想我混淆的部分是线程——我假设长时间运行的事务(DoStuff())将在不同的线程上执行,而它不必这样做。我也不知道这个反应框架,但是当doSuffE()在一个不同的线程上发生时,它看起来非常有用。谢谢你的回复:“我认为这并不能使我得到我想要的结果,但是它仍然是一个有趣的模式。
DoStuff().Subscribe(result => { /* handle result */ };
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;
    }
}