Getter 中的 VB.NET 调用 Setter

发布于 2024-11-27 06:38:32 字数 864 浏览 3 评论 0原文

我有一个这样的类:

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

Getter 正在计算平均值并调用 Setter 来保存该值。由于某种原因我无法理解,平均值始终为 0。例如:

Dim c As New Class2()
c.Add(1)
c.Add(2)
c.Add(3)
Console.WriteLine(c.Avg.ToString()) ' This will print 0

我做错了什么吗?这是什么原因呢?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

仙女 2024-12-04 06:38:32

哇,我想你已经发现了 VB 的一个非常奇怪的行为:当你在函数的定义中时,你可以使用 Return 返回一个值任一 通过使用=来“设置”函数的值。

像这样:

Function GetInteger() As Integer
    GetInteger = 5
End Function

在上面的函数中,GetInteger = 5行基本上相当于Return 5*。

好的,所以您可能已经知道了。但这是奇怪的部分,直到现在测试它之前我都不知道情况是这样的(诚然,在 Mono ,但我看到了与您相同的行为):显然这也适用于属性获取器。所以看看这一行:

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

您实际上没有在那里调用属性设置器;您正在为 getter 设置返回值。您可以通过删除行 Return _avg; 来验证这一点突然你会看到你的 getter 开始返回实际的平均值。

*不完全相同,因为您可以稍后将 GetInteger 设置为其他内容而不立即返回,而使用 Return 可确保函数正确返回离开。

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.

白馒头 2024-12-04 06:38:32

这是设计使然,并且在 Visual Basic 语言规范第 9.7.1 章中明确提到:

一个特殊的局部变量,在Get中隐式声明
访问器主体的声明空间与属性同名,
表示属性的返回值。局部变量有
在表达式中使用时的特殊名称解析语义。如果
局部变量在需要表达式的上下文中使用
分类为方法组,例如调用表达式,则
名称解析为函数而不是局部变量。
例如:

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

通过直接分配 _avg 字段来解决您的问题。最好避免具有此类副作用的属性获取器。

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.

谢绝鈎搭 2024-12-04 06:38:32

您的 setter 和 getter 实际上应该只返回属性,而不是自己进行计算。尝试创建一个像 calcAvg() 这样的方法来执行平均值计算,并在 Add() 上调用该方法(该方法在内部不应重新执行整个平均值计算,但如果您不确定如何执行此操作,请告诉我)。该 calcAvg() 方法将设置 _avg 实例变量。

另外,我不确定它是否真的能让发送者拥有平均的二传手。数字的平均值是派生属性,不应该由外部用户设置。

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.

往昔成烟 2024-12-04 06:38:32

MrDanA 的答案比我要给你的更正确,但是,我相信你得到 0 值的原因是因为你从未将变量 _avg 设置为任何值。进行 AVG 计算后,如果您这样做:

_avg = AVG
return _avg

当我这样做时,我得到的值为 2。

正如我之前所说,MrDanA 的答案是一个更好的方法。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文