SynchronizationContext.发送来调用一个返回结果的函数

本文关键字:一个 返回 结果 函数 调用 SynchronizationContext | 更新日期: 2023-09-27 18:13:04

我在当前的一个项目中有一个简单的组件,可以从visual studio工具箱中删除到WinForms应用程序中的窗体和用户控件上。

它工作得很好,只是包装了ISupportInitialize期间捕获的SynchronizationContext的Send和Post方法。BeginInit (UI Context).

下面是该组件最简单的现有代码。

public class SyncContextComponent : Component, ISupportInitialize
{
    private SynchronizationContext _context;
    public SyncContextComponent() { }
    public SyncContextComponent(IContainer container)
    {
        container.Add(this);
    }
    void ISupportInitialize.BeginInit()
    {
        _context = SynchronizationContext.Current; // context of creator
    }
    void ISupportInitialize.EndInit() { }
    /// <summary>
    /// Dispatches an <b>asynchronous</b> message to <see cref="Context"/>
    /// </summary>
    /// <param name="action">The delegate to call</param>
    /// <example>
    /// uiContext.Post(() => this.WorkOnUiControls());
    /// </example>
    public void Post(Action action)
    {
        _context.Post(new SendOrPostCallback(_ => action()), null);
    }
    /// <summary>
    /// Dispatches an <b>synchronous</b> message to <see cref="Context"/>
    /// </summary>
    /// <param name="action">The delegate to call</param>
    /// <example>
    /// uiContext.Send(() => this.WorkOnUiControls());
    /// </example>
    public void Send(Action action)
    {
        _context.Send(new SendOrPostCallback(_ => action()), null);
    }
}
我现在需要扩展它来支持返回值,并且正在寻找各种方法…

我很想了解以下三种处理方法的含义,以及是否有"更好"的方法。

注意:我使用的例子是调用一个函数,它接受1个参数arg1,并返回TResult,即Func<T1, TResult>。一旦我知道了最好的方法,我打算扩展它,所以我有从Func<TResult>Func<T1,T2....T9,TResult>的9个参数的重载,以及Action重载。

Send0:第一种方式-是我已经在做的一个简单的扩展:

    public TResult Send0<T1, TResult>(Func<T1, TResult> func, T1 arg1)
    {
        TResult retval = default(TResult);
        _context.Send(new SendOrPostCallback((x) =>
        {
            retval = func(arg1);
        })
        , null);
        return retval;
    }

Send1:第二种方法-是由研究和查看stackoverflow上的其他信息提示的,这暗示我可能应该通过使用state参数来获得结果。我想,如果是这种情况,我可能也需要对输入参数做同样的事情,所以我得到了以下内容:

    private class SendFuncState1<T1, TResult>
    {
        public TResult Result { get; set; }
        public T1 Arg1 { get; set; }
    }
    public TResult Send1<T1, TResult>(Func<T1, TResult> func, T1 arg1)
    {
        SendFuncState1<T1, TResult> state = new SendFuncState1<T1, TResult>()
        {
            Arg1 = arg1
        };
        _context.Send(new SendOrPostCallback((x) =>
        {
            var state0 = (SendFuncState1<T1, TResult>)x;
            state0.Result = func(state0.Arg1);
        })
        , state);
        return state.Result;
    }

Send2:第三次尝试-我想既然我正在传递参数,也许我应该传递函数本身?无论如何,我得到了以下内容:

    private class SendFuncState2<T1, TResult>
    {
        public Func<T1, TResult> Func { get; set; }
        public TResult Result { get; set; }
        public T1 Arg1 { get; set; }
    }
    public TResult Send2<T1, TResult>(Func<T1, TResult> func,
        T1 arg1)
    {
        SendFuncState2<T1, TResult> state = new SendFuncState2<T1, TResult>()
        {
            Func = func,
            Arg1 = arg1
        };
        _context.Send(new SendOrPostCallback((x) =>
        {
            var state0 = (SendFuncState2<T1, TResult>)x;
            state0.Result = state0.Func(state0.Arg1);
        })
        , state);
        return state.Result;
    }
所以,我把它放到一个小的测试应用程序中,从后台线程更新WinForms控件测试每个方法,并在每个方法的10k次迭代上做了一些秒表来测试各种方法的速度(只是使用字符串作为参数和返回值)。他们都工作得很好,在那个简单的测试中表现一样。不确定使用非平凡输入/输出类型时会是什么样子。

所以- Send0很好-其余的只是无关紧要/混乱没有理由吗?或者我应该考虑其他的——或者其他的?

SynchronizationContext.发送来调用一个返回结果的函数

他们都工作得很好

是的,它们都有效。使用最简单的一个——第一个。编译器为您(基本上)将第一种转换为第二种。lambda在CLR级别不存在。为您创建了一个隐藏的闭包类,并且重写了局部变量访问以访问该类的字段。

具有相同的性能

我肯定他们没有,但是通过消息循环运行Windows Message太慢了,它完全支配了你正在做的简单操作。没有必要优化这个