每次触发事件时是否需要实例化一个新的自定义事件参数?

Is it necessary to instantiate a new custom eventarg each time the event is fired?

我有一个 WinForms 应用程序,它使用带有自定义事件参数的事件来更新 MainForm 上的状态面板。

我在我的 class 中声明我的活动,如下所示:

Public Event BomNotLoaded As EventHandler(Of StatusEventArgs)

当事件被触发时,我这样称呼它:

OnBomNotLoaded(New StatusEventArgs(2, "Please scan a SKU/UPC First!", Color.Red, Color.White))

Protected Overridable Sub OnBomNotLoaded(ByVal e As StatusEventArgs)
    RaiseEvent BomNotLoaded(Me, e)
End Sub

在 MainForm 代码中,我有这个:

Private Sub _station_BomNotLoaded(sender As Object, e As StatusEventArgs) Handles _station.BomNotLoaded
    SetStatus(e)
    _alert.InvalidScan()
End Sub

SetStatus 方法然后使用 StatusEventArgs 中的值来设置标签文本、图像以及标签背景颜色和标签文本颜色。该图像源自第一个数字作为代码编号。

我是否需要在每次触发此事件时都实例化一个新的 StatusEventArgs?还有其他方法可以提供更好的性能吗?

我问的原因是这个应用程序是 运行 在单声道下的 RaspberryPi3 上,我遇到了 cpu 使用率高的性能问题。

事实上,将单个对象创建为初始化并对其进行修改然后传递给每个事件调用应该不会有什么坏处。 Event 将在引发时创建并发送指向 EventArgs 对象的指针的副本。 Event Args 毕竟是一个 ByVal 声明。在标准行为中,EventArgs 对象被创建使用,然后被释放。在这种情况下,对于几个周期,内存中实际上有 2 个对 EventArgs 对象的引用。各种属性的重量始终如一地保持,而不是只在需要使用时使用。这也存在 eventargs 实例在被事件处理程序使用之前被调用代码修改的风险。

现在,要改变行为,有几个选项,选项意味着选择、好处和缺点。

第一个建议不好,但可行。如果您在使用前检查事件处理程序的事件对象是否为 NOTHING,那么您可以在 eventargs 为 nothing 的情况下引发事件。但这是一个糟糕的设计范例,因为它出乎意料。我们假设 EventArgs 对象将是某物。

Private Sub _station_BomNotLoaded(sender As Object, e As StatusEventArgs) Handles _station.BomNotLoaded
   If e IsNot Nothing Then 
      SetStatus(e)
      _alert.InvalidScan()
   End If 
End Sub

正如我所说,我认为这是一个坏主意,因为它的行为方式出乎意料。

或者,如果您 modify/create 您需要什么事件,那么您可以为每个事件描述事件签名。

如果您添加了一个事件,例如 "BomNotScanned",它没有与之关联的事件参数 class,那么您可以引发该事件以及针对特定场景处理它的任何事件的 SKU/UPC 未被扫描。然后,对于数据不符合预期的其他情况,您仍然可以使用 BomNotLoaded。

这样做的缺点是使事件结构更加复杂。在某些情况下是预期的,在其他情况下则不是。

另一种可能性是在数据不符合预期的情况下抛出异常(例如SKU/UPC未被扫描),而仅在数据为'good.'的情况下使用事件该场景使用代码在函数中内联处理它,而不是在其他地方弹出的事件。这有一个缺点,即异常包含堆栈信息,并且可能比事件更严重地影响性能。

最后,关于您目前的工作方式,还有一些选项可能会以小的方式影响性能。

首先,您将事件状态的上下文线索从对象传递到表单。您的 StatusEventArg 具有这 4 个参数,其中两个是我假设您用于警报消息的颜色。我假设的第一个是某种类型的识别标志。

IMO,你应该让你的 UI 根据识别标志标记这些颜色(即 2 给你红色背景,白色文本是粗体,而 1 会显示正常重量的黑色文本白色背景等)。这创建了关注点分离,并阻止扫描器 class 指示主窗体如何响应事物。

同样,用描述字符串代替定义的枚举标志意味着您来回传递的信息更少,从而提高了效率。这意味着您只发送一个整数,而不是从 class 向表单发送 3 个整数和一个字符串。

最后,您可以为 StatusEventArgs 构建您的新方法,使其不接受参数而只定义特定的基本状态(比如 Good 状态)。然后您可以使用 WITH(作为对象初始值设定项)来设置任何给定场景所需的那些参数。

例如,考虑这个 class 定义:

Public class StatusEventArgs
   Inherits EventArgs 

   Public Sub New()
     Flag = 1 
     Random1 = "Random Text" 
     Random2 = ""
   End Sub 

   Public Property Flag AS Integer 
   Public Property Random1 As String
   Public Property Random2 As String 
End Class

然后我可以通过以下方式实例化它:

Dim se1 As new StatusEventArgs With {.Flag = 2, .Random1="Bob Denver"} 
Dim se2 As New StatusEventArgs With {.Random1 = "Hello", .Random2="World" }

事实上,这并没有真正为您节省任何性能方面的费用,但它确实意味着您只需要更改默认值的值定义。

综上所述,我不确定所定义逻辑的任何方面是否会产生性能问题,除非您过于频繁地引发事件。也就是说,我对 Raspberry PI 等嵌入式系统并不过分熟悉。