在Single-Threaded Apartment中运行代码并返回值,我无法设置当前的公寓模型

时间:2015-08-10 21:25:21

标签: c# .net multithreading

我有一个需要在单公寓线程上下文中进行的调用,但我不能保证在我的代码中设置[STAThread]因为我不控制入口点和我的代码将通过反思来调用。

我想出了这种调用调用并返回令牌的方法,但我希望有更好的方法:

private static string token;

private static Task<string> GetToken(string authority, string resource, string scope) // I don't control this signature, as it gets passed as a delegate
    {
        Thread t = new Thread(GetAuthToken);

        t.SetApartmentState(ApartmentState.STA);
        t.Start();
        t.Join();

        return Task.Run(() =>
        {
            return token; 
        });
    }

    private static void GetAuthToken()
    {
        Credentials creds = AuthManagement.CreateCredentials(args); // this call must be STA
        token = creds.Token;
    }

我的约束:

  • 第一种方法的签名必须Task<string> MyMethod(string, string, string)
  • AuthManagement.CreateCredentials(args) 必须在单线程公寓环境中调用
  • 当前线程上下文不能保证是STA,因此应该假定为MTA。

我需要调用该方法,使其保证为STA,并返回结果。

感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

有一种更好的方法。您必须创建一个新线程以保证您在STA线程上,因为您无法在启动后更改线程的公寓状态。但是,您可以摆脱Thread.Join()调用,以便使用TaskCompletionSource实际异步您的方法:

private static async Task<string> GetToken(string authority, string resource, string scope) // I don't control this signature, as it gets passed as a delegate
{
    using (var tcs = new TaskCompletionSource<string>()) {
        Thread t = new Thread(() => GetAuthToken(tcs));
        t.SetApartmentState(ApartmentState.STA);
        t.Start();
        var token = await tcs.Task
        return token;
    }
}

private static void GetAuthToken(TaskCompletionSource<string> tcs)
{
    try {
       Credentials creds = AuthManagement.CreateCredentials(args); // this call must be STA
       tcs.SetResult(creds.Token);
    }
    catch(Exception ex) {
       tcs.SetException(ex);
    }
}

此外,如果您需要在任务中包含返回值,请使用Task.FromResult()代替Task.Run()