gpt4 book ai didi

c# - 是否可以将异步方法作为 c# 中事件处理程序的回调?

转载 作者:太空狗 更新时间:2023-10-29 22:59:45 25 4
gpt4 key购买 nike

下面的例子说明了我的设计。有一个 while true 循环做某事并通过一个事件通知它已经对所有订阅者做了某事。我的应用程序在完成通知所有订阅者之前不应继续执行,只要有人不在回调中放置异步无效,它就可以工作。

如果有人在回调上放置一个 async void 来等待某个任务,那么我的循环可以在回调完成之前继续。我还能做些什么设计来避免这种情况。

它的第 3 方插件注册主题并订阅事件,所以我无法控制他们是否放置异步无效。可以理解,我不能为 EventHandler 执行任务回调,所以我有什么替代方案可以使用 .net 4.5。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication4
{
public class Test
{

public event EventHandler Event;

public void DoneSomething()
{
if (Event != null)
Event(this,EventArgs.Empty);
}
}
class Program
{
static void Main(string[] args)
{
var test = new Test();

test.Event += test_Event;
test.Event +=test_Event2;

while(true)
{
test.DoneSomething();
Thread.Sleep(1000);

}
}

private static void test_Event2(object sender, EventArgs e)
{
Console.WriteLine("delegate 2");
}

static async void test_Event(object sender, EventArgs e)
{
Console.WriteLine("Del1gate 1");

await Task.Delay(5000);

Console.WriteLine("5000 ms later");

}
}
}

最佳答案

If someone put a async void on the callback to await some task, then my loop can continue before the callback is completed. What other designs can I do to avoid this situation.

这真的没有办法避免。即使您以某种方式“知道”订阅者不是通过 async/await 实现的,您仍然无法保证调用者没有构建某种形式异步“操作”到位。

例如,一个完全正常的 void 方法可以将其所有工作放入 Task.Run 调用中。

My application should not continue its execution before its done notifying all subscribers

您的当前版本确实遵循此契约(Contract)。您同步通知订阅者 - 如果订阅者异步执行某些操作以响应该通知,那是您无法控制的事情。


Understandable I cant do Task callbacks for the EventHandler, so what alternatives do I have with .net 4.5.

请注意,这实际上是可能的。例如,您可以将上面的内容重写为:

public class Program
{
public static void Main()
{
var test = new Test();

test.Event += test_Event;
test.Event +=test_Event2;

test.DoneSomethingAsync().Wait();
}
}

public delegate Task CustomEvent(object sender, EventArgs e);

private static Task test_Event2(object sender, EventArgs e)
{
Console.WriteLine("delegate 2");
return Task.FromResult(false);
}

static async Task test_Event(object sender, EventArgs e)
{
Console.WriteLine("Del1gate 1");
await Task.Delay(5000);
Console.WriteLine("5000 ms later");
}

public class Test
{
public event CustomEvent Event;
public async Task DoneSomethingAsync()
{
var handler = this.Event;
if (handler != null)
{
var tasks = handler.GetInvocationList().Cast<CustomEvent>().Select(s => s(this, EventArgs.Empty));
await Task.WhenAll(tasks);
}
}
}

您也可以按照 svick 的建议使用事件添加/删除重写它:

public class Test
{
private List<CustomEvent> events = new List<CustomEvent>();
public event CustomEvent Event
{
add { lock(events) events.Add(value); }
remove { lock(events) events.Remove(value); }
}

public async Task DoneSomething()
{
List<CustomEvent> handlers;
lock(events)
handlers = this.events.ToList(); // Cache this
var tasks = handlers.Select(s => s(this, EventArgs.Empty));
await Task.WhenAll(tasks);
}
}

关于c# - 是否可以将异步方法作为 c# 中事件处理程序的回调?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19506217/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com