在Visual studio中,是否可能(以及如何)使VB.net编译器在方法调用中将withevents字段用作byref参数?
标题说明一切 请阅读完整的编译示例代码:在Visual studio中,是否可能(以及如何)使VB.net编译器在方法调用中将withevents字段用作byref参数?,vb.net,compilation,byref,Vb.net,Compilation,Byref,标题说明一切 请阅读完整的编译示例代码: Imports System.Runtime.CompilerServices Imports System.ComponentModel Imports System.Drawing Public Class PropertyChangedNotifier Implements INotifyPropertyChanged Protected Sub SetProperty(Of T)(ByRef _backingStoreFiel
Imports System.Runtime.CompilerServices
Imports System.ComponentModel
Imports System.Drawing
Public Class PropertyChangedNotifier
Implements INotifyPropertyChanged
Protected Sub SetProperty(Of T)(ByRef _backingStoreField As T, ByVal new_value As T, <CallerMemberName> Optional ByVal propertyname As String = "")
' PropertyChangedNotifier allow me to add functionality here like
' PropertyChanging with old and new value
' Locked current object is property IsReadOnly is true etc ...
' Save Old Original values
' etc
' Let's keep it simple for example
_backingStoreField = new_value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyname))
End Sub
Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
End Class
Public Class VehicleEngine
Public Property OilWarningAlert As Boolean
Public Event OilWarningAlertChanged As EventHandler
' [...]
End Class
Public Interface IBulbReadOnly
ReadOnly Property State As Boolean
End Interface
' just a light bulb on car dashboard
Public Class Bulb
Implements IBulbReadOnly
Public Property State As Boolean 'true => On, false => Off
Public Sub New(color As Color)
End Sub
Public ReadOnly Property StateAsReadOnly As Boolean Implements IBulbReadOnly.State
Get
Return State
End Get
End Property
End Class
Public Class Car
' this base class has methods to handle changed & chagnging event, dirty state etc
' It implements INotifyPropertyChanged
Inherits PropertyChangedNotifier
Public Property Engine() As VehicleEngine
Get
Return _Engine
End Get
Set(ByVal value As VehicleEngine)
SetProperty(_Engine, value)
' The line above compile fine but actually the generated code is
' Dim tempEngine = _Engine
' SetProperty(tempEngine, value)
' _Engine = tempEngine
' So when SetProperty raise event the value is not changed in current car instance
End Set
End Property
Private WithEvents _Engine As VehicleEngine
Public ReadOnly Property OilWarningBulb As IBulbReadOnly
Get
Return _OilWarningBulb
End Get
End Property
Private _OilWarningBulb As Bulb = New Bulb(Color.Red) ' display warning to driver
Private Sub Engine_OilWarningChanged(ByVal sender As Object, ByVal e As EventArgs) Handles _Engine.OilWarningAlertChanged
'When we change engine, we synchronize all other Car composites objects
_OilWarningBulb.State = Engine.OilWarningAlert
End Sub
Private Sub OnPropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs) Handles Me.PropertyChanged
If (e.PropertyName = "Engine") Then
Engine_OilWarningChanged() ' Synchronize the new engine with the car objects
End If
End Sub
' [...]
End Class
Module Test
Sub Main()
Dim car As Car = New Car()
Dim bad_engine = New VehicleEngine()
bad_engine.OilWarningAlert = True
car.Engine = bad_engine
End Sub
End Module
实际上由vb编译器处理为以下代码块:
Dim tempEngine = _Engine
SetProperty(tempEngine, value)
_Engine = tempEngine
因此,当SetProperty引发事件时,当前汽车对象仍具有旧引擎。。。这是空/无
我不喜欢非显式代码
所以我想阻止编译器生成这样的临时字段。。。
并让它考虑用WestVunes声明的字段,不适合作为方法调用中的ByRF参数使用。
在我看来,这是编译器应该具备的行为
你知道怎么做吗?你的车可能没有发动机。从未创建过VehicleEngine实例创建了车辆引擎请参见代码段末尾,但问题是旧的VB问题-WithEvents变量由VB编译器作为属性实现,VB在传递属性ByRef时复制。此链接适用于VB6,但仍然适用:它是CLR限制,不支持通过引用传递事件或属性等访问器。C编译器声明了一个错误,VB.NET编译器解决了它。请注意,您正在编写错误代码,Car.Engine\u OilWarningChanged事件处理程序没有EventHandler事件处理程序的相应签名。更糟糕的是,它假定事件是由于应打开警告而引发的。但事实并非如此,您只是因为引擎被重新分配而引发事件。代码太复杂,这会导致类似这样的错误。@DaveDoknjas:我知道withevents是一个syntaxic sugar关键字,它创建了一个用于管理句柄的属性。。。。关于类方法。问题是,我们在代码中看到一个字段,但却得到一个属性。。。在我看来,所见即所得/所见即所得不够明确。在我看来,因为编译器负责将其转换为属性,所以当开发人员认为它是一个字段时,它应该负责警告开发人员,并根据它是一个字段的事实编写代码,例如:使用byref。@HansPassant谢谢,我更正了关于事件签名的问题。关于代码,我删除了一些检查和测试,比如:仅当引擎发生更改时引发事件,在使用它之前检查引擎是否为null等等。
Dim tempEngine = _Engine
SetProperty(tempEngine, value)
_Engine = tempEngine