c# - SynchronizationContext.Send 调用 Func 返回结果

标签 c# .net winforms ui-thread synchronizationcontext

我在当前项目中有一个简单的组件,可以将其从 visual studio 工具箱中拖放到 WinForms 应用程序中的 Forms 和 UserControls 上。

它按原样运行良好 - 并简单地包装了在 ISupportInitialize.BeginInit(拥有表单/控件的 UI 上下文)期间捕获的 SynchronizationContext 的发送和发布方法。

这是该组件的最简单形式的现有代码。

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);
    }
}

我现在需要扩展它以支持返回值,并且正在研究各种方法...

我有兴趣了解以下 3 种处理方式的含义,以及是否有“更好”的方式。

注意:我使用的示例是调用一个函数,该函数接受 1 个参数 arg1,并返回 TResult ,即 Func<T1, TResult> .一旦我知道最好的方法,我打算扩展它,所以我有覆盖 Func<TResult> 的重载最多可能有 9 个参数 Func<T1,T2....T9,TResult> ,以及 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 上的其他信息提示,这暗示我可能应该通过使用状态 arg 来获得结果。我想如果是这样的话——我可能也需要对输入参数做同样的事情,所以我得到了以下信息:

    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:第三次尝试 - 我想既然我传递了 args,也许我也应该传递 Func 本身?无论如何 - 我得到了以下信息:

    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 是否正常 - 其余的只是无关紧要/无缘无故地乱七八糟? 或者我应该考虑其中之一 - 还是其他什么?

最佳答案

They all worked fine

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

had the same performance

我敢肯定他们没有,但是通过消息循环运行 Windows 消息太慢了,以至于它完全支配了您正在执行的简单操作。对此进行优化毫无意义。

关于c# - SynchronizationContext.Send 调用 Func 返回结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32595630/

相关文章:

python - 在 Python .Net 中将 C# 字节数组转换为 numpy 数组

c# - 使用 BackgroundWorker 卡住表单

c# - 为什么在一种特定情况下,Bing map 上只显示我的 Pin 图的子集?

c# - 使用 CRM SDK 时 log4net 的 FileLoadException

.net - System.Timers.Timer 与 System.Threading.Timer

c# - 内存泄漏 : TimerCallbacks objects referenced by root

c# - Monitor.TryEnter/Monitor.Exit 和 SynchronizationLockException

.net - 在winform中进行初始化工作的更好地方在哪里?

c# - SqlDataReader.Read 和 SqlDataReader.NextResult 之间的区别

c# - 计算列表中属性的总和