编程VB.NET 开发者

如何在 Visual Basic 中实现支持计算值的属性(Calculated Properties),以及如何安全地与属性内部的私有字段交互?

用 Hintsage AI 助手通过面试

回答。

问题的背景
Visual Basic 中的属性允许封装获取和设置值的逻辑。引入属性后,代码变得更具可读性和安全性,消除了对类字段的直接访问需求,并简化了在对象中实现验证或计算逻辑。

问题
初学者常常将字段设为公共,或使用没有 getter/setter 的自动属性,这会导致封装的破坏或无法实现计算值。另一个问题是属性内部的递归调用,导致 StackOverflow。

解决方案
在 Visual Basic 中,声明一个私有字段,属性包括带有所需逻辑的 Get 和 Set 块。计算属性只使用 Get,返回基于私有字段的计算值。在 set 块中始终应访问私有字段,以避免无限递归。

代码示例:

Private _price As Decimal Private _quantity As Integer Public Property Total As Decimal Get Return _price * _quantity ' 计算属性 End Get End Property Public Property Price As Decimal Get Return _price End Get Set(value As Decimal) If value < 0 Then Throw New ArgumentException("价格必须为正") _price = value End Set End Property

关键特点:

  • 封装对内部数据的访问。
  • 在获取/赋值时添加验证逻辑或附加处理的能力。
  • 区分只读属性和可写属性。

具有挑战性的问题。

在 Set Price 中可以访问属性 Name 吗?如果它同样通过私有字段实现?

可以,如果在 Price 的 set 块中访问另一个属性(例如,Name),这是允许的,因为对不同私有字段的访问不会导致递归。应避免对自身的访问:在 Set Price 中调用 Price 将导致递归。

代码示例:

Public Property Name As String Get Return _name End Get Set(value As String) _name = value End Set End Property Public Property Price As Decimal Get Return _price End Get Set(value As Decimal) If Name Is Nothing Then _name = "default" _price = value End Set End Property

如果在属性的 Get 块中再次调用该属性会发生什么?

这将导致无限递归和 StackOverflow。在 get 块中始终使用私有字段,否则属性将调用自身。

Public Property Amount As Decimal Get Return Amount ' 将导致无限递归 End Get Set(value As Decimal) _amount = value End Set End Property

是否可以声明仅用于写入的属性(WriteOnly),这有什么危险?

存在 WriteOnly 属性,但不推荐使用,因为对象失去了返回值的能力,这降低了可读性和可预测性。如果仅用于写入,最好重新考虑架构。

Private _secret As String Public WriteOnly Property Secret As String Set(value As String) _secret = value ' 可以写入,无法获取。 End Set End Property

常见错误和反模式

  • 在属性内部递归调用自身,而不是访问私有字段。
  • 使用公共字段而不是属性,违反封装。
  • 在没有明确需求的情况下创建 WriteOnly 属性。
  • 在 set 块中缺乏输入数据验证。

生活中的例子

消极案例

程序员决定将 Price 字段设为公共并直接使用它,结果 Price 有时错误地变为负值。

优点:

  • 实现迅速,代码量最小。

缺点:

  • 没有封装。
  • 验证逻辑无法实现。
  • 容易引入不合法值。

积极案例

同事将 Price 替换为具有私有字段和 set 块中的验证的属性,这防止了不正确的值。

优点:

  • 数据安全性。
  • 代码发展的灵活性。

缺点:

  • 代码量略微增加。