问题
Title says it all...
Please read this full compiling sample code :
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
At first sight, this code seems fine for non expert VB.net developpers But it actually throws a NullReferenceException when settings car.Engine !
I do understand why this happens. This is because the line :
SetProperty(_Engine, value)
is actually handled by vb compiler as this block of code :
Dim tempEngine = _Engine
SetProperty(tempEngine, value)
_Engine = tempEngine
So when SetProperty raise event the current car object has still the old Engine ... (which is null/Nothing)
I dont like non explicit code So i would like to prevent compiler to generate temporary field like that... And make it consider field declared with withevents ineligible to be used as byref argument in a method call. This is, in my opinion, the behavior the compiler should have to have.
Do you know any way to do that ?
来源:https://stackoverflow.com/questions/24632610/in-visual-studio-is-it-possible-and-how-to-make-vb-net-compiler-handles-the