0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SynchronizationContext越えの呼び出し

Last updated at Posted at 2024-12-02

0. はじめに

Freeradicalの中の人、yamarahです。
以前の記事(Autodesk Inventor API Hacking (NET環境での別スレッドUI))の続きというか、その後の経過です。

1. SynchronizationContext越えの呼び出し

不幸にも複数のUIスレッドを持つ場合に、

// 待たない。投げっぱなし。
context.Post(_ => action(), null);
// 完了するまでロックする。
context.Send(_ => action(), null);

だと、不便です。具体的にはawaitしたい。
もっと言えば、呼び出し先の例外も受けたい。
ということで、標準化しました。

using System;
using System.Threading;
using System.Threading.Tasks;

public static class CallOverSynhronizationContextHelper
{
    public static async Task InvokeActionAsync(Action action, SynchronizationContext context)
    {
        Exception? exception = null;
        var sem = new SemaphoreSlim(0, 1);
        context.Post(_ =>
        {
            try
            {
                action();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            finally
            {
                _ = sem.Release();
            }
        }, null);
        await sem.WaitAsync();
        if (exception is not null) throw exception;
    }
    public static async Task InvokeAsyncActionAsync(Func<Task> actionAsync, SynchronizationContext context)
    {
        Exception? exception = null;
        var sem = new SemaphoreSlim(0, 1);
        context.Post(async _ =>
        {
            try
            {
                await actionAsync();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            finally
            {
                _ = sem.Release();
            }
        }, null);
        await sem.WaitAsync();
        if (exception is not null) throw exception;
    }
    public static async Task<T> InvokeFunctionAsync<T>(Func<T> func, SynchronizationContext context)
    {
        Exception? exception = null;
        var sem = new SemaphoreSlim(0, 1);
        T? result = default;
        context.Post(_ =>
        {
            try
            {
                result = func();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            finally
            {
                _ = sem.Release();
            }
        }, null);
        await sem.WaitAsync();
        return exception is null ? result! : throw exception;
    }
    public static async Task<T> InvokeAsyncFunctionAsync<T>(Func<Task<T>> funcAsync, SynchronizationContext context)
    {
        Exception? exception = null;
        var sem = new SemaphoreSlim(0, 1);
        T? result = default;
        context.Post(async _ =>
        {
            try
            {
                result = await funcAsync();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            finally
            {
                _ = sem.Release();
            }
        }, null);
        await sem.WaitAsync();
        return exception is null ? result! : throw exception;
    }
}

戻り値も取れるし、とても幸せ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?