开发者

VB.NET Call Setter from within Getter

开发者 https://www.devze.com 2023-03-23 16:49 出处:网络
I have a class like this: Public Class MyClass Private _intList As New List(Of Integer) Private _avg As Decimal

I have a class like this:

Public Class MyClass

Private _intList As New List(Of Integer)
Private _avg As Decimal

Public Sub Add(ByVal anInt As Integer)
    _intList.Add(anInt)
End Sub

Public Property Avg() As Decimal
    Get
        Dim _sum As Integer = 0
        For Each anInt In _intList
            _sum += anInt
        Next
        Avg = If((_intList.Count > 0), _sum / _intList.Count, _avg)
        Return _avg
    End Get
    Set(ByVal value As Decimal)
        If _avg <> value Then
            _avg = value
            Console.WriteLine("Value changed")
        End If
    End Set
End Property

End Class

The Getter is calculating average and calls Setter to save the value. For some reason I cannot understand, the average is always 0. For example:

Dim c As New Class2()
c.Add(1)
c.Add(2)
c.Add(3)
Console.WriteLine(c.开发者_开发知识库Avg.ToString()) ' This will print 0

Did I do something wrong? What is the cause of this?


Wow, I think you've discovered a very strange behavior of VB: when you are inside the definition of a function, you can return a value either with Return or by using = to "set" the function's value.

Like this:

Function GetInteger() As Integer
    GetInteger = 5
End Function

In the above function, the line GetInteger = 5 is basically equivalent to Return 5*.

OK, so you probably already knew that. But here's the weird part, and I had no idea this was the case until testing it just now (admittedly, on Mono, but I am seeing the same behavior you are): apparently this applies to property getters as well. So look at this line:

Avg = If((_intList.Count > 0), _sum / _intList.Count, _avg)

You're actually not calling the property setter there; you're setting the return value for the getter. You can verify this by removing the line Return _avg; suddenly you will see your getter starts returning the actual average.

*Not exactly the same, as you could later set GetInteger to something else without returning immediately whereas using Return ensures the function returns right away.


This is by design and explicitly mentioned in the Visual Basic Language Specification, chapter 9.7.1:

A special local variable, which is implicitly declared in the Get accessor body's declaration space with the same name as the property, represents the return value of the property. The local variable has special name resolution semantics when used in expressions. If the local variable is used in a context that expects an expression that is classified as a method group, such as an invocation expression, then the name resolves to the function rather than to the local variable. For example:

ReadOnly Property F(i As Integer) As Integer
    Get
        If i = 0 Then
            F = 1    ' Sets the return value.
        Else
            F = F(i - 1) ' Recursive call.
        End If
    End Get
End Property

Solve your issue by assigning the _avg field directly. Property getters with side-effects like this is best avoided.


Your setters and getters really should just be returning properties, and not doing the calculations themselves. Try creating a method like calcAvg() that does the average calculations, and on the Add() call that method (which should internally not re-perform the whole average calculation, but simply update it. Let me know if you're not sure how to do that). That calcAvg() method will set the _avg instance variable.

Also, I'm not sure it really makes send to have a setter for the average. An average of numbers is a derived property, not something that should be set by an external user.


MrDanA answer is more correct than what I'm going to give you, however, I believe the reason why you are getting the value of 0 is because you are never setting the variable _avg to anything. After you do your AVG calculation if you do:

_avg = AVG return _avg

I get a value of 2 when I do this.

Like I said before though... MrDanA's answer is a better way to go.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号