【问题标题】:Run code and return value in a Single-Threaded Apartment, where I can't set current apartment model在无法设置当前公寓模型的单线程公寓中运行代码并返回值
【发布时间】:2015-08-11 05:49:54
【问题描述】:

我有一个需要在单公寓线程上下文中进行的调用,但我不能通过在我的代码中设置 [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&lt;string&gt; MyMethod(string, string, string)
  • AuthManagement.CreateCredentials(args) 必须在单线程公寓上下文中调用
  • 当前线程上下文不能保证为 STA,因此应假定为 MTA。

我需要以保证它是 STA 的方式调用该方法,并返回一个结果。

感谢您的帮助!

【问题讨论】:

    标签: c# .net multithreading


    【解决方案1】:

    有一个更好的方法。您必须创建一个新线程以保证您在 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()

    【讨论】:

    • 我所做的 (Task.Run(() =&gt; {return n;})) 和 Task.FromResult() 有什么区别?
    • Task.Run 将在线程池上运行 return n 语句,然后完成任务。 Task.FromResult 将立即创建一个已完成的任务对象,而无需运行任何额外的代码或在线程池线程上运行..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多