始终同步执行未知动作

问题描述

我目前正在研究模拟类库,其他程序员将使用该类来创建动态模拟时间轴并运行这些模拟。

从某种意义上讲,这是通过让库的用户指定模拟时间内特定点的动作来完成的。

但是我现在遇到了一个问题,即用户创建的动作可能是异步的,也可能是异步的。为了使仿真保持一致,尽管我需要同步执行两个变体。我把问题归结为一个非常简单的例子:

class Program
{
    static void Main()
    {
        Action action = ActionFromUser();

        action();

        Console.WriteLine("2");

        Console.ReadKey();
    }

    static Action ActionFromUser()
    {
        Random rng = new Random();

        if (rng.Next(0,2) == 0) // 50/50
        {
            return async () =>
            {
                await Task.Delay(1000);
                Console.WriteLine("1");
            };
        }
        else
        {
            return () =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("1");
            };
        }

    }
}

现在的问题归结为输出取决于操作是异步还是同步,这是我要摆脱的行为。

该操作将始终没有参数且没有返回值。

不想使用反射(action.Method.IsDefined(typeof(AsyncStateMachineAttribute),...)。

我尝试从Action切换到delegateFunc似乎不是一个好选择,因为我必须指定一个返回值类型),但是我在那里什么都没找到那会帮助我。

解决方法

Action上的异步lambda async void。您极不可能想要这个。如有疑问,请将其更改为Func<Task>,并在 synchronous 结果上返回一个完成的任务,然后将结果await返回。

注意:这是一个人为的示例,我想您的代码有很大不同,但是它说明了这一点:

static Func<Task> FromUserAsync()
{
    Random rng = new Random();

    if (rng.Next(0,2) == 0) // 50/50
    {
        return async () =>
        {
            await Task.Delay(1000);
            Console.WriteLine("1");
        };
    }
    else
    {
        return () =>
        {
            Thread.Sleep(1000);
            Console.WriteLine("1");
            return Task.CompletedTask;
        };
    }

}

最后一点,您可能应该使用Task.FromException

捕获同步路径中的所有异常并将其放置在任务上