发送参数后异步等待事件

3

I have the following code:

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());
}

我知道第一次自动登录是一个异步请求,我需要“等待”。

登录成功将触发:

public event Host.LoginSuccessEventHandler LoginSuccess

登录失败将触发以下情况:

public event Host.LoginFailureEventHandler LoginFailure

一个通用的通知将通过以下方式触发:

public event Host.NotificationEventHandler Notification

我该如何处理并正确等待登录成功或失败呢?
第一次自动登录尝试未显示我已连接,而第二个手动登录窗口确实成功了(因此我可以认为我的凭据是正确的,现在只是代码没有正确“等待”)。

2
这能解决你的问题吗?我认为可以。 - usr
@usr 很抱歉这样做,但您能否再详细解释一下?我不确定如何实现建议中的内容。 - jason m
1个回答

6

我会使用一个TaskCompletionSource<T>来封装可以从Host.Login触发的事件,并将其作为Host类型周围的扩展方法:

public static class HostExtensions
{
    public static 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;
    }
}

如果通知消息很重要,您可以创建一个名为LoginDetails的类型,并将其用作TaskCompletionSource的返回类型:
public class LoginDetails
{
    public bool IsSuccess { get; set; }
    public string Notification { get; set; }
}

并像这样使用它:

public static 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;
}

现在你可以在 LoginAsync 上使用 await
var login = await host.LoginAsync(APIServerType.Simulator, "T4Example", "112A04B0-5AAF-42F4-994E-FA7CB959C60B");

顺便说一句,如果你在Console应用程序中使用此功能,你需要使用Result而不是await(这会将控制权返回给调用者) 在Main中, 这有点可惜,因为这样就会失去异步调用的全部意义:

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

你好,这段代码中存在一些错误。例如 return tcs.Task; 这行代码提示“return 关键字后面不能跟对象表达式”。你有什么想法吗? - jason m
修复了我的代码。这些方法应该分别返回 Task<bool>Task<LoginDetails> - Yuval Itzchakov
1
谢谢,我会在这个周末查看。很抱歉还没有接受。非常感谢您花时间调整代码。 - jason m
你不需要在返回值上加上 await 吗?(return await tcs.Task;) - Abhijith C R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接