C# 在c中如何阻止直到触发事件#

C# 在c中如何阻止直到触发事件#,c#,events,C#,Events,询问之后,我想知道是否可以等待触发事件,然后获取事件数据并返回部分数据。有点像这样: private event MyEventHandler event; public string ReadLine(){ return event.waitForValue().Message; } ... event("My String"); ...elsewhere... var resp = ReadLine(); ManualResetEvent oSignalEvent = new Manual

询问之后,我想知道是否可以等待触发事件,然后获取事件数据并返回部分数据。有点像这样:

private event MyEventHandler event;
public string ReadLine(){ return event.waitForValue().Message; }
...
event("My String");
...elsewhere...
var resp = ReadLine();
ManualResetEvent oSignalEvent = new ManualResetEvent(false);

void SecondThread(){
    //DoStuff
    oSignalEvent.Set();
}

void Main(){
    //DoStuff
    //Call second thread
    System.Threading.Thread oSecondThread = new System.Threading.Thread(SecondThread);
    oSecondThread.Start();

    oSignalEvent.WaitOne(); //This thread will block here until the reset event is sent.
    oSignalEvent.Reset();
    //Do more stuff
}
var foo = new Foo();

ThreadPoolScheduler.Instance
    .Schedule(
        TimeSpan.FromSeconds(5.0),
        () => foo.SendLine("Bar!"));

var resp = foo.ReadLine();

Console.WriteLine(resp);
请确保您提供的任何解决方案都直接返回值,而不是从其他地方获取。我想问的是,上述方法在某种程度上是否可行。我知道Auto/ManuelResetEvent,但我不知道它们是否像上面那样直接返回值

更新:我使用
MyEventHandler
(其中包含
消息
字段)声明了一个事件。我在另一个名为
ReadLine
的线程中有一个方法,正在等待事件触发。当事件激发时,WaitForValue方法(事件处理场景的一部分)返回事件args,其中包含消息。然后,ReadLine将消息返回给任何调用它的对象

我问他我做了什么,但感觉不太对劲。在ManuelResetEvent触发和程序检索并返回数据之间,几乎感觉数据可能发生了什么

更新:自动/手动重置事件的主要问题是它太容易受到攻击。线程可能会等待事件,然后在将其更改为其他内容之前,没有足够的时间让其他人获得它。有没有办法使用锁或其他东西?可能使用get和set语句。

您可以使用。在启动次线程之前重置事件,然后使用该方法阻止当前线程。然后,您可以让次线程设置ManualResetEvent,这将导致主线程继续。大概是这样的:

private event MyEventHandler event;
public string ReadLine(){ return event.waitForValue().Message; }
...
event("My String");
...elsewhere...
var resp = ReadLine();
ManualResetEvent oSignalEvent = new ManualResetEvent(false);

void SecondThread(){
    //DoStuff
    oSignalEvent.Set();
}

void Main(){
    //DoStuff
    //Call second thread
    System.Threading.Thread oSecondThread = new System.Threading.Thread(SecondThread);
    oSecondThread.Start();

    oSignalEvent.WaitOne(); //This thread will block here until the reset event is sent.
    oSignalEvent.Reset();
    //Do more stuff
}
var foo = new Foo();

ThreadPoolScheduler.Instance
    .Schedule(
        TimeSpan.FromSeconds(5.0),
        () => foo.SendLine("Bar!"));

var resp = foo.ReadLine();

Console.WriteLine(resp);

您可以等待的一种非常简单的事件是
ManualResetEvent
,更好的是
ManualResetEventSlim

他们有一个
WaitOne()
方法,可以完全做到这一点。您可以永远等待,或者设置一个超时,或者设置一个“取消令牌”,这是您决定停止等待事件的一种方式(如果您想取消您的工作,或者您的应用程序被要求退出)

您可以通过调用
Set()
来触发它们


是文档。

如果您乐于使用Microsoft反应式扩展,那么这可以很好地工作:

public class Foo
{
    public delegate void MyEventHandler(object source, MessageEventArgs args);
    public event MyEventHandler _event;
    public string ReadLine()
    {
        return Observable
            .FromEventPattern<MyEventHandler, MessageEventArgs>(
                h => this._event += h,
                h => this._event -= h)
            .Select(ep => ep.EventArgs.Message)
            .First();
    }
    public void SendLine(string message)
    {
        _event(this, new MessageEventArgs() { Message = message });
    }
}

public class MessageEventArgs : EventArgs
{
    public string Message;
}

我需要在另一个线程上调用
SendLine
消息以避免锁定,但此代码显示它按预期工作。

如果当前方法是异步的,则可以使用TaskCompletionSource。创建事件处理程序和当前方法可以访问的字段

    TaskCompletionSource<bool> tcs = null;

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        tcs = new TaskCompletionSource<bool>();
        await tcs.Task;
        WelcomeTitle.Text = "Finished work";
    }

    private void Button_Click2(object sender, RoutedEventArgs e)
    {
        tcs?.TrySetResult(true);
    }


while循环怎么样:
while(someGlobalvar)
cahnge
someGlobalvar
在一个函数中,你可以登录到事件。它是活动的等待,这是一个非常糟糕的解决方案,除了这个问题早于那个问题:)@Vahid,自从我问这个问题以来,又有7年的编程经验,我想说,如果你不得不这么做,你可能做错了。最好指定一个回调。如果您使用的是不允许任何其他操作(如COM)的旧系统,则只需让代码等待ManualResetEvent并设置第二个事件以保护写入,直到所有线程都读取完毕。我还建议您签出。这不会直接返回值。我已经在另一个问题上试过了。这不是我想问的吗?但这不会返回任何值。你能编辑qu并添加不同组件及其交互的概述吗?它将帮助我们更好地了解您试图实现的目标,并有望改进设计。您不需要异步来使用TaskCompletionSource这是真的,但是如果您想在不阻塞UI的情况下等待任务,您确实需要它。可以重置TaskCompletionSource吗?@KyleDelaney否。在我的示例中,您将使用新实例替换tcs。您如何使用非按钮单击的事件来进行此操作?是否有一种方法可以调用事件,等待处理程序完成执行,然后在结束时调用TrySetResult(true)?