SynchronizationContext.Send 调用函数返回结果
SynchronizationContext.Send to call a Func returning a result
我在当前项目中有一个简单的组件,可以从 visual studio 工具箱中将其拖放到 WinForms 应用程序中的表单和用户控件上。
它按原样工作得很好 - 并且简单地包装了在 ISupportInitialize.BeginInit 期间捕获的 SynchronizationContext 的 Send 和 Post 方法(UI 拥有 Form/Control 的上下文)。
这是该组件的最简单形式的现有代码。
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);
}
}
我现在需要扩展它以支持 returning 值,并且正在研究各种方法...
我有兴趣了解以下 3 种处理方式的含义,如果有 "better" 方式。
注意:我使用的示例是调用一个函数,该函数接受 1 个参数 arg1,并且 returns TResult
,即 Func<T1, TResult>
。一旦我知道最好的方法,我打算扩展它,所以我有覆盖从 Func<TResult>
到 Func<T1,T2....T9,TResult>
的 9args 的重载,以及 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:第二种方式 - 由对此进行研究并查看 Whosebug 上的其他信息提示,这暗示我可能应该通过使用状态 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 次迭代做了一些秒表以测试各种方法的速度(仅使用字符串作为参数和 return 值)
它们都运行良好,并且在那个简单的测试中具有相同的性能。
虽然不确定使用非平凡 input/output 类型时会是什么样子。
所以 - Send0 好吗 - 其余的只是无关紧要/无缘无故地乱七八糟?
或者我应该考虑其中之一 - 还是其他?
They all worked fine
是的,它们都有效。使用最简单的 - 第一个。编译器为你把第一个变成第二个(基本上)。 CLR 级别不存在 Lambda。为您创建了一个隐藏的闭包 class,并且重写了局部变量访问以访问该 class 的字段。
had the same performance
我确定他们没有,但是 运行 通过消息循环的 Windows 消息太慢了,以至于它完全控制了您正在执行的简单操作。优化这个没意义。
我在当前项目中有一个简单的组件,可以从 visual studio 工具箱中将其拖放到 WinForms 应用程序中的表单和用户控件上。
它按原样工作得很好 - 并且简单地包装了在 ISupportInitialize.BeginInit 期间捕获的 SynchronizationContext 的 Send 和 Post 方法(UI 拥有 Form/Control 的上下文)。
这是该组件的最简单形式的现有代码。
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);
}
}
我现在需要扩展它以支持 returning 值,并且正在研究各种方法...
我有兴趣了解以下 3 种处理方式的含义,如果有 "better" 方式。
注意:我使用的示例是调用一个函数,该函数接受 1 个参数 arg1,并且 returns TResult
,即 Func<T1, TResult>
。一旦我知道最好的方法,我打算扩展它,所以我有覆盖从 Func<TResult>
到 Func<T1,T2....T9,TResult>
的 9args 的重载,以及 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:第二种方式 - 由对此进行研究并查看 Whosebug 上的其他信息提示,这暗示我可能应该通过使用状态 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 次迭代做了一些秒表以测试各种方法的速度(仅使用字符串作为参数和 return 值) 它们都运行良好,并且在那个简单的测试中具有相同的性能。 虽然不确定使用非平凡 input/output 类型时会是什么样子。
所以 - Send0 好吗 - 其余的只是无关紧要/无缘无故地乱七八糟? 或者我应该考虑其中之一 - 还是其他?
They all worked fine
是的,它们都有效。使用最简单的 - 第一个。编译器为你把第一个变成第二个(基本上)。 CLR 级别不存在 Lambda。为您创建了一个隐藏的闭包 class,并且重写了局部变量访问以访问该 class 的字段。
had the same performance
我确定他们没有,但是 运行 通过消息循环的 Windows 消息太慢了,以至于它完全控制了您正在执行的简单操作。优化这个没意义。