锅炉板代码更换 – 这个代码有什么不好的吗?
我最近创建了这两个(不相关的)方法来替换我的winforms应用程序中的大量样板代码。 据我所知,他们工作正常,但我需要一些保证/建议,以确定是否存在一些我可能会遗漏的问题。
(从记忆里)
static class SafeInvoker { //Utility to avoid boiler-plate InvokeRequired code //Usage: SafeInvoker.Invoke(myCtrl, () => myCtrl.Enabled = false); public static void Invoke(Control ctrl, Action cmd) { if (ctrl.InvokeRequired) ctrl.BeginInvoke(new MethodInvoker(cmd)); else cmd(); } //Replaces OnMyEventRaised boiler-plate code //Usage: SafeInvoker.RaiseEvent(this, MyEventRaised) public static void RaiseEvent(object sender, EventHandler evnt) { var handler = evnt; if (handler != null) handler(sender, EventArgs.Empty); } }
编辑:请在此处查看相关问题
UPDATE
继死锁问题( 此问题中相关)之后,我已从Invoke切换到BeginInvoke(请参阅此处的说明)。
另一个更新
关于第二个片段,我越来越倾向于使用’空委托’模式,它通过直接用空处理程序声明事件来解决这个’源’问题,如下所示:
event EventHandler MyEventRaised = delegate {};
这是件好事。 使它们成为扩展方法,以便更多地清理代码。 例如:
//Replaces OnMyEventRaised boiler-plate code //Usage: SafeInvoker.RaiseEvent(this, MyEventRaised) public static void Raise(this EventHandler eventToRaise, object sender) { EventHandler eventHandler = eventToRaise; if (eventHandler != null) eventHandler(sender, EventArgs.Empty); }
现在,您可以致电:myEvent.Raise(this);
由于事实,Benjol不知道,为什么他将Action放入MethodInvoker并且broccliman意图将它用作扩展函数,这里是清理代码:
static class SafeInvoker { //Utility to avoid boiler-plate InvokeRequired code //Usage: myCtrl.SafeInvoke(() => myCtrl.Enabled = false); public static void SafeInvoke(this Control ctrl, Action cmd) { if (ctrl.InvokeRequired) ctrl.BeginInvoke(cmd); else cmd(); } //Replaces OnMyEventRaised boiler-plate code //Usage: this.RaiseEvent(myEventRaised); public static void RaiseEvent(this object sender, EventHandler evnt) { var temp = evnt; if (temp != null) temp(sender, EventArgs.Empty); } }
最后一点: MethodInvoker
和Action
都只是具有完全相同结构的委托。 由于这种情况,两者都可以相互替换。 这个命名冲突的根源来自遗产。 最初(.Net 2.0)只有MethodInvoker
和Action(T)
。 但是由于事实,所有使用Action(T)
人都会有一个Action
并且发现使用MethodInvoker
非常不自然。 所以在.Net 3.5中Action
, Action(T1, T2, T3, T4)
以及所有Func
委托也加入了,但MethodInvoker在不做任何重大更改的情况下无法再删除。
额外:
如果你能够使用.Net 3.5,上面的代码就可以了,但如果你被固定到.Net 2.0,你可以像以前一样使用它作为普通函数,并用MethodInvoker
替换Action
。
类似的模式对我没有任何问题。 我不知道你为什么要在MethodInvoker中包装Action。