Results 1 to 5 of 5

Thread: Property setter not called when setting individual element of an array property.

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Sep 2016
    Posts
    22

    Property setter not called when setting individual element of an array property.

    Hi,

    I'm using VisualStudio 2022 working in VB.Net targeting .NET framework 4.8.1
    I have a class with a public property that is an array.
    There is a private backing variable that is an array.
    I want to fire an event when the property is changed.
    When I pass a value to a single index of the array, the index is actually set without the setter ever being called.
    My main issue is that the setter is not called so my data changed event does not fire.
    But I am also curious how the private variable gets set without the setter being called.

    If I build the array ahead of time and pass the whole array to the property at once the setter IS called.
    So I have a workaround. But that's not really how I want to do it as the individual values may be set in different sections of code.
    For instance, I may use a loop to initialize the data in the array but then later change single indices as conditions warrant.

    Can someone explain why this happens and how to fix it?

    Here is a simple console app that demonstrates the issue.

    Code:
    Module Module1
        Sub Main()
            Console.WriteLine($"Adding feet one at a time.{vbCrLf}")
            Dim Monster1 As New Thing
            For Index As Integer = 1 To 17
                Monster1.Feet(Index) = New Foot(Index)
            Next
            Console.WriteLine($"Notice that the property setter was never called.{vbCrLf} But output below indicates the property was set.")
            For I As Integer = 1 To 17
                Console.WriteLine($"Foot Number {Monster1.Feet(I).FootNum} was created.")
            Next
            Console.WriteLine($"{vbCrLf}{vbCrLf}Adding feet all at once.")
            Dim Monster2 As New Thing
            Dim Feet(17) As Foot
            For Index As Integer = 1 To 17
                Feet(Index) = New Foot(Index)
            Next
            Monster2.Feet = Feet
            Console.WriteLine($"Notice that the property setter was called.{vbCrLf}")
            Console.Write("Press any key to continue...")
            Console.ReadKey(True)
        End Sub
        Class Thing
            Private _Feet(17) As Foot
            Public Property Feet As Foot()
                Get
                    Return _Feet
                End Get
                Set(value As Foot())
                    Console.WriteLine("Foot property setter is called.")
                    _Feet = value
                    OnFeetChanged()
                End Set
            End Property
            Private Sub OnFeetChanged()
                ' Raise Event
            End Sub
        End Class
        Class Foot
            Private _FootNum As Integer
            Public ReadOnly Property FootNum As Integer
                Get
                    Return _FootNum
                End Get
            End Property
            Public Sub New(FootNumber As Integer)
                _FootNum = FootNumber
            End Sub
        End Class
    End Module
    And here is the console output:

    Adding feet one at a time.

    Notice that the property setter was never called.
    But output below indicates the property was set.
    Foot Number 1 was created.
    Foot Number 2 was created.
    Foot Number 3 was created.
    Foot Number 4 was created.
    Foot Number 5 was created.
    Foot Number 6 was created.
    Foot Number 7 was created.
    Foot Number 8 was created.
    Foot Number 9 was created.
    Foot Number 10 was created.
    Foot Number 11 was created.
    Foot Number 12 was created.
    Foot Number 13 was created.
    Foot Number 14 was created.
    Foot Number 15 was created.
    Foot Number 16 was created.
    Foot Number 17 was created.


    Adding feet all at once.
    Foot property setter is called.
    Notice that the property setter was called.

  2. #2
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,744

    Re: Property setter not called when setting individual element of an array property.

    Property setters don’t work with collections, lists, or arrays. There’s no way to pass an index. You could probably work something out with an observable collection. I can’t explain at the moment, but this link might help…

    https://www.codeproject.com/Articles...mply-Explained

  3. #3
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,775

    Re: Property setter not called when setting individual element of an array property.

    Why would you expect a setter to be executed when you're not setting the property? If you have a property that is an array and you set an element in that array then you're not setting the property. You're getting the property and then setting an element on the array you get. This:
    Code:
    Feet(Index) = New Foot(Index)
    never assigns anything to Feet, so of course the setter is not executed. That code is functionally equivalent to this:
    Code:
    Dim var = Feet 'Get the Feet property value.
    
    var(Index) = New Foot(Index)
    You execute the property getter to get the array object, then setting the element of that object has nothing at all to do with the property.

    One option would be to not expose the array itself via the property but only store it internally and then use an indexed property:
    Code:
    Class Thing
        Private _Feet(17) As Foot
        Public Property Feet(index As Integer) As Foot
            Get
                Return _Feet(index)
            End Get
            Set(value As Foot)
                Console.WriteLine("Foot property setter is called.")
                _Feet(index) = value
                OnFeetChanged()
            End Set
        End Property
        Private Sub OnFeetChanged()
            ' Raise Event
        End Sub
    End Class
    You then can't access the array itself via the property, so setting an element by index will invoke the property setter and the getter will only get one element at a time by index. If you wanted to be able to access the entire array, you could add a method that would return it or, probably better, a copy of it.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  4. #4
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,744

    Re: Property setter not called when setting individual element of an array property.

    Ok, I was wrong about the index, but property getters and setters aren’t ideal for arrays, as jmcilhinney has shown you.
    Have a look at ReadOnly and WriteOnly Properties and OverLoading Properties. You could set the array elements in a WriteOnly Property, and retrieve the array from an Overloaded ReadOnly Property.

  5. #5
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,744

    Re: Property setter not called when setting individual element of an array property.

    Here's what i meant...

    Code:
    Private _feet([ubound of array]) As Foot
    Public Overloads WriteOnly Property Feet(ByVal index As Integer) As Foot
        Set(ByVal value As Foot)
            _feet(index) = value
        End Set
    End Property
    
    Public Overloads ReadOnly Property Feet() As Foot()
        Get
            Return _feet
        End Get
    End Property

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width