(我知道标题听起来很简单,但等等——这可能不是你认为的问题。)
在 VB.NET 中,我能够编写自定义事件。例如,我有一个单独的线程,它会定期引发一个事件,并且在该事件上需要更新 GUI。我不想让忙碌的线程打扰 UI 计算,也不想将 Me.Invoke(Sub() ...) 放在事件处理程序中,因为它也是从 GUI 线程调用的。
我想出了这段非常有用的代码。 GUI 线程将设置 EventSyncInvoke = Me(主窗体)。然后线程可以像往常一样简单地引发事件 TestEvent ,无需特殊代码,它将在 GUI 线程上无缝执行:
Private TestEventDelegate As EventHandler
Public EventSyncInvoke As System.ComponentModel.ISynchronizeInvoke
Public Custom Event TestEvent As EventHandler
AddHandler(value As EventHandler)
TestEventDelegate = [Delegate].Combine(TestEventDelegate, value)
End AddHandler
RemoveHandler(value As EventHandler)
TestEventDelegate = [Delegate].Remove(TestEventDelegate, value)
End RemoveHandler
RaiseEvent(sender As Object, e As System.EventArgs)
If EventSyncInvoke IsNot Nothing Then
EventSyncInvoke.Invoke(TestEventDelegate, {sender, e})
Else
TestEventDelegate.Invoke({sender, e})
End If
End RaiseEvent
End Event
现在在 C# 中,我可以做到这一点:
public event EventHandler TestEvent
add
{
testEventDelegate = (EventHandler)Delegate.Combine(testEventDelegate, value);
}
remove
{
testEventDelegate = (EventHandler)Delegate.Remove(testEventDelegate, value);
}
}
但是定制提升的能力在哪里?
最佳答案
其他答案告诉我一个事实,我不能直接在 C# 中做到这一点,但不是我为什么不能和为什么我不想这样做的理由。我花了一段时间才理解 C# 事件与 VB.NET 相比是如何工作的。所以这个解释是为了其他没有很好理解的人开始沿着正确的思路思考。
老实说,我已经习惯了样板文件 OnTestEvent
格式,以至于我不太喜欢让它与其他辅助方法不同的想法。 :-) 但是现在我明白了基本原理,我发现它实际上是放置这些东西的最佳位置。
VB.NET 允许您使用 RaiseEvent
关键字隐藏调用委托(delegate)的背景细节。 RaiseEvent
调用事件委托(delegate)或自定义事件的自定义 RaiseEvent
部分。
在 C# 中,没有 RaiseEvent
。引发一个事件基本上只不过是调用一个委托(delegate)。没有自定义 RaiseEvent
部分可以无缝调用,当你正在做的所有事情都是调用一个委托(delegate)时。所以对于 C# 来说,自定义事件就像骨架,实现了事件的添加和删除,但没有实现引发它们的能力。这就像必须用自定义 RaiseEvent
部分的代码替换所有 TestEvent(sender, e)
RaiseEvent
。
对于正常事件, raise 大致类似于 NormalEvent(sender, e)
。但是一旦您放入自定义添加和删除,您就必须使用您在添加和删除中使用的任何变量,因为编译器不再这样做了。这就像 VB.NET 中的自动属性:一旦您手动放入 getter 和 setter,您必须声明和处理您自己的局部变量。因此,不要使用 TestEvent(sender, e)
,而是使用 testEventDelegate(sender, e)
。这就是您重新路由事件委托(delegate)的地方。
我将从 VB.NET 迁移到 C# 与必须用自定义 RaiseEvents
代码替换每个 RaiseEvent
进行了比较。 RaiseEvent
代码段基本上是一个事件和一个辅助函数组合在一起。 在 protected RaiseEvent
方法中,在 VB.NET 或 C# 中只有一个 OnTestEvent
实例并调用该方法引发事件实际上是标准的。这允许任何可以访问 protected (或私有(private)或公共(public))OnTest E
通风口的代码引发事件。对于你想做的事情,只要把它放在方法中就更容易、更简单并且性能稍好一些。这是最佳实践。
现在,如果您真的想要(或需要)以某种方式模仿 VB.NET 的 RaiseEvent 细节隐藏调用 SomeDelegate(sender, e)
并让魔法发生,您可以简单地将细节隐藏在第二个委托(delegate)中:NiceTestEvent = (sender, e) => eventSyncInvoke.Invoke(testEventDelegate, new object[] { sender, e });
现在您可以拨打 NiceTestEvent(sender, e)
。但是,您将无法拨打 TestEvent(sender, e)
。 TestEvent
仅用于外部代码添加和删除,Visual Studio 会告诉您。
关于c# - 相当于 C# 中 VB 的自定义 RaiseEvent 块?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9342523/