在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