创建类似 Action.Invoke 的方法

Create a method like Action.Invoke

我正在尝试编写一个简单的方法来使代码更具可读性。我正在写一个我有异步任务的部分,所以我使用 Action 作为我的方法的参数,以便在方法完成时获得回调的可能性。

总之我的签名总是这样的:

public void myAsyncMethod(...params..., Action<other params> onFinish = null)

我使用默认的 Action 为 null 只是为了给库用户更多的灵活性,但在我的实现中我总是写这段代码:

if (onFinish != null)
{
    UnityMainThreadDispatcher.Instance().Enqueue(
        () => onFinish(other params)
    );
}

这是因为在 unity 中,我提供了在主线程上启动 Action 的可能性,以防用户需要与图形循环交互。 我的想法是:我可以将那段代码放在方法中以使方法实现更具可读性吗? 以这样的方式调用那个东西真的很棒:

onFinish?.InvokeOnMainThread(other params);

有点像Action?.Invoke方式。 所以我在 c# 中做了一些关于扩展方法、动作和泛型的搜索,但我无法掌握如何构建一个带有泛型的方法来完成我想要达到的目标。 我真的不知道要搜索什么才能达到我的目标,我环顾四周,但可能我还不够好,无法将这些概念组合在一起以达到我的目标。

到目前为止我的想法是这样的(行不通):

public static void InvokeOnMainThread(this Action<T1, T2>, T1 t1, T2 t2){ ... }
public static void InvokeOnMainThread<Action, T1, T2>(Action<T1, T2>, T1 t1, T2 t2){ ... }

我使用带有 2 个参数的 Action 只是因为在我的情况下这是最常见的,但我需要带有 0 到 4 个参数的相同调用(但我认为当我掌握了这个概念时它会很容易扩展,或者至少我可以复制它以获得我需要的参数数量)。

您需要为 0-4 个可能的参数创建单独的扩展方法,如下所示:

public static partial class UnityExtensions
{
    public static void InvokeOnMainThread(this Action onFinish)
    {
        if (onFinish != null) // Or throw ArgumentNullException() if you prefer
            UnityMainThreadDispatcher.Instance().Enqueue(() => onFinish());
    }
    
    public static void InvokeOnMainThread<T1>(this Action<T1> onFinish, T1 t1)
    {
        if (onFinish != null)
            UnityMainThreadDispatcher.Instance().Enqueue(() => onFinish(t1));
    }
    
    public static void InvokeOnMainThread<T1, T2>(this Action<T1, T2> onFinish, T1 t1, T2 t2)
    {
        if (onFinish != null)
            UnityMainThreadDispatcher.Instance().Enqueue(() => onFinish(t1, t2));
    }
    
    public static void InvokeOnMainThread<T1, T2, T3>(this Action<T1, T2, T3> onFinish, T1 t1, T2 t2, T3 t3)
    {
        if (onFinish != null)
            UnityMainThreadDispatcher.Instance().Enqueue(() => onFinish(t1, t2, t3));
    }
    
    public static void InvokeOnMainThread<T1, T2, T3, T4>(this Action<T1, T2, T3, T4> onFinish, T1 t1, T2 t2, T3 t3, T4 t4)
    {
        if (onFinish != null)
            UnityMainThreadDispatcher.Instance().Enqueue(() => onFinish(t1, t2, t3, t4));
    }
}

然后你就可以做到:

onFinish?.InvokeOnMainThread(param1, param2); // Or however many parameters you have.

Can I have a variable number of generic parameters?, c# does not allow for variable numbers of generic parameters. This is why e.g. there are distinct Tuple.Create<>() 方法中所述,每个支持的参数数量。