发送参数后异步等待事件

jas*_*n m 3 .net c# asynchronous task-parallel-library async-await

我有以下代码:

static void Main(string[] args)
{
    moHost = new Host(
        APIServerType.Simulator,
        "T4Example",
        "112A04B0-5AAF-42F4-994E-FA7CB959C60B",
        "CTS",
        "myUser",
        "myPass");  //automated login

    moHost = Host.Login(
        APIServerType.Simulator,
        "T4Example",
        "112A04B0-5AAF-42F4-994E-FA7CB959C60B"); //manual login window
    moAccounts = moHost.Accounts;

    System.Console.WriteLine(moAccounts.ToString());
}
Run Code Online (Sandbox Code Playgroud)

我知道第一次自动登录是发送的异步请求,我需要"等待".

登录成功将触发:

public event Host.LoginSuccessEventHandler LoginSuccess
Run Code Online (Sandbox Code Playgroud)

登录失败会触发:

public event Host.LoginFailureEventHandler LoginFailure
Run Code Online (Sandbox Code Playgroud)

通用通知将由以下方式触发:

public event Host.NotificationEventHandler Notification
Run Code Online (Sandbox Code Playgroud)

如何处理此问题并正确等待登录成功或失败?

第一次自动登录尝试没有显示我连接,而第二个手动登录窗口确实成功(因此我可以认为我的凭据很好,现在只是代码没有正确'等待').

Yuv*_*kov 5

我会用一个TaskCompletionSource<T>包可以从触发事件Host.Login,并把它作为一个Extension MethodHost类型:

public static class HostExtensions
{
    public static async Task<bool> LoginAsync(this Host host, APIServerType serverType, string name, string id)
    {
        var tcs = new TaskCompletionSource<bool>();
        try
        {
            host.LoginSuccess += (object obj, LoginSuccessEventHandler e) =>
            {
                tcs.SetResult(true);
            }

            host.LoginFailure += (object obj, LoginFailureEventHandler e) =>
            {
                tcs.SetResult(false);
            }
        }
        catch (Exception e)
        {
            tcs.SetException(e);
        }

        host.Login(serverType, name, id);
        return tcs.Task;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果通知消息很重要,您可以创建一种LoginDetails类型,并将其用作以下类型的返回类型TaskCompletionSource:

public class LoginDetails
{
    public bool IsSuccess { get; set; }
    public string Notification { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

public static async Task<LoginDetails> LoginAsync(this Host host, APIServerType serverType, string name, string id)
{
    var tcs = new TaskCompletionSource<LoginDetails>();
    var loginDetails = new LoginDetails();
    try
    {
        host.LoginSuccess += (object obj, LoginSuccessEventHandler e) =>
        {
            loginDetails.IsSuccess = true;
            tcs.SetResult(loginDetails);
        }

        host.LoginFailure += (object obj, LoginFailureEventHandler e) =>
        {
            loginDetails.IsSuccess = false;
            tcs.SetResult(loginDetails);
        }

        host.Notification += (object obj, NotificationEventHandler e) =>
        {
            loginDetails.Notificaiton = e.Notification // I assume it would look something like this
            tcs.SetResult(loginDetails);
        }
    }
    catch (Exception e)
    {
        tcs.SetException(e);
    }

    host.Login(serverType, name, id);
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)

现在你可以使用awaitLoginAsync.

var login = await host.LoginAsync(APIServerType.Simulator, "T4Example", "112A04B0-5AAF-42F4-994E-FA7CB959C60B");
Run Code Online (Sandbox Code Playgroud)

在旁注中,如果你在一个Console应用程序中使用Result它,你将不得不使用哪个将阻塞而不是await(它产生控制回到调用者)里面Main,这有点遗憾,因为它会错过异步的全部内容要求:

var login = host.LoginAsync(APIServerType.Simulator, "T4Example", "112A04B0-5AAF-42F4-994E-FA7CB959C60B").Result;
Run Code Online (Sandbox Code Playgroud)