Warm tip: This article is reproduced from stackoverflow.com, please click
.net properties vb.net

Calling property Setter from within Getter does not execute Setter?

发布于 2020-03-27 10:21:02

I have a string property within a class. The Setter for the property is supposed to do some important external operations whenever the property's value is modified.

In some circumstances, the Getter itself is supposed to modify the property's value before returning it. When it does this, I still want the important operations within the Setter to be executed.

However, whenever I have the Getter of my property attempt to change the property's value, the Setter is skipped altogether.

Below is some mock-up code that demonstrates what I'm seeing:

Sub Main()
    Dim att As New Attribute

    ' The following line should "do important stuff"
    ' (and it does).
    att.Value = "FOO"

    ' The following line sould add "BAR" to the end and "do important stuff"
    ' (it does neither).
    Dim getValue As String = att.Value

    MsgBox("Value: " & getValue)
End Sub

Class Attribute
    Private _value As String = ""

    Public Property Value As String
        Get
            ' Modify value using Setter.
            Value = _value & "BAR"

            ' Return value.
            Return _value
        End Get
        Set(setVal As String)
            ' Do important stuff.
            MsgBox("Doing important stuff!")
            '...

            ' Set value.
            _value = setVal
        End Set
    End Property
End Class

When I run debugging with a breakpoint on the "Get" line, you can see that the Value = _value & "BAR" line does NOT cause the setter to execute. Instead, it just modifies the value of the Value variable in memory, rather than actually executing the Setter.

Is this by design? If so, any explanation as to why?

Can I tweak my code or change a setting somewhere to make my Setter be executed when called from the Getter?


PS, I'm aware I could write a separate function for setting the value and call that from both the Getter and the Setter. My reason for posting is because I want to avoid that extra overhead if possible.


EDIT 7/3/2019 @ 8:50 AM This is similar to this question. The accepted answer on that post does answer the question of "is this by design and why?", but I'm not sure I understand it. Some additional explanation would be appreciated.

In addition, none of the answers on that post answer the second part of my question, "Can I tweak my code to somehow call the Setter from within the Getter?" This was my main reason for posting a new question.


EDIT 7/3/2019 @ 9:10 AM I'm adding someting closer to my real class below to demonstrate why I'm doing it like this:

(Note: the Attribute object is a class of object that belongs to the software that I'm writing this add-in for. It's impossible for me to modify or inherit it. So instead I'm writing a "Definition" class that "extends" it with additional functionality.)

Class AttributeDefinition
    Public AttributeName As String
    Private AttributeSet As Inventor.AttributeSet

    Sub New(AttributeName As String, AttributeSet As Inventor.AttributeSet)
        Me.AttributeName = AttributeName
        Me.AttributeSet = AttributeSet

        If AttributeSet.NameIsUsed(AttributeName) Then
            AttributeObject = AttributeSet.Item(AttributeName)
        End If
    End Sub

    Private AttributeObject As Inventor.Attribute

    Property Value() As String
        Get
            If AttributeObject Is Nothing Then
                Value = ""
            End If

            Return AttributeObject.Value
        End Get
        Set(setVal As String)
            If AttributeObject Is Nothing Then
                ' Create Attribute with empty string as value.
                ' (In actuality, this taks much more than just one line of code).
                AttributeObject = AttributeSet.Add(AttributeName, Inventor.ValueTypeEnum.kStringType, setVal)
            Else
                AttributeObject.Value = setVal
            End If
        End Set
    End Property
End Class

In short, the Getter checks if the Attribute actually exists before trying to return its value. If it doesn't, it calls the Setter to create it.

The Setter is fully responsible for setting the Attribute's value, including creating it with the specified value if it doesn't exist. This is actually very involved (more than one line of code), so I don't want to duplicate it in another method. I also don't want to create a separate dedicated method for it, unless calling the Setter from the Getter is impossible.

Questioner
DRoam
Viewed
88
djv 2019-07-03 22:21

Just add Me. before assigning Value and it will invoke the setter

Public Property Value As String
    Get
        ' Modify value using Setter.
        Me.Value = _value & "BAR"
        ' Return value.
        Return _value
    End Get
    Set(setVal As String)
        ' Do important stuff.
        MsgBox("Doing important stuff!")
        '...
        ' Set value.
        _value = setVal
    End Set
End Property

enter image description here