VBA中公共变量和属性的区别

11

什么是两者之间的区别?

Public Variable As Integer

Private pVariable As Integer

Public Property Let Variable(ByVal lVariable As Integer)
    pVariable = lVariable
End Property

Public Property Get Variable()
    Variable = pVariable
End Property

在VBA类模块中?

为什么我要使用第二个版本?


2
第二种方法(属性)允许外部访问,就像该字段是公共的一样,同时允许类过滤数据。对于 Let 属性,它可能会检查有效性,例如不接受负体积。对于 Get 属性,它可能会计算一个在类中实际上不存在的“变量”,例如 mass Get 属性 可能会返回密度乘以体积的乘积。您还可以通过省略 Let 或 Get 属性使属性只读(或仅写 - 不常用)。 - riderBill
2个回答

25

尽管VBA是面向对象的,但在很多方面仍然有限制。不过,就这个例子而言,了解VBA中OOP的基础应该已经足够了。

你的代码

Private pVariable As Integer

Public Property Let Variable(ByVal lVariable As Integer)
    pVariable = lVariable
End Property

Public Property Get Variable()
    Variable = pVariable
End Property

is wrong a bit unnecessary是有点不必要的。

注意:在处理错误/验证传入数据时,您可以这样做,但通常如果只是简单地设置和获取值,则不会这样做

如果您同时公开了Let/Set和Get属性,为什么还需要私有后备字段?对于此操作,您只需要公共变量本身,无需使用属性。

当您只需要公开其中一个属性而不是另一个属性(即仅setter或getter)时,情况就会完全改变。也许通过一个示例更容易理解...

示例

让我们从一个简单的“银行”示例开始工作(显然,您在现实生活中不会在VBA中这样做,但它是一个评估基础概念的好方法

想象一下,您需要构建一个类来模拟银行账户。您需要一种方式来从账户中存款取款以及显示余额

通常,您不会为balance字段拥有setter,因为不应允许任何人明确set余额。(如果您知道一个允许这样做的银行,请告诉我;))。实际余额应该是一个私有变量。应该有一个公开它的属性,这就是您应该考虑的全部。

考虑一个VBA类(一个接口)

IAccountServices.cls

Sub Deposit(amount As Double)
End Sub

Sub WithDraw(amount As Double)
End Sub

还需要另一个类来表示账户

Account.cls

Implements IAccountServices

' balance should be private
' cause you should only have a getter for it
' you should only be able to set the balance inside this class
' based on the operations
Private accBalance As Double

' see Getter only - no setter
Public Property Get Balance() As Double
    Balance = accBalance
End Property

Public Function Deposit(amount As Double)
    accBalance = accBalance + amount
End Function

Public Function WithDraw(amount As Double)
    accBalance = accBalance - amount
End Function

Private Sub IAccountServices_Deposit(amount As Double)
    accBalance = accBalance + amount
End Sub

Private Sub IAccountServices_WithDraw(amount As Double)
    accBalance = accBalance - amount
End Sub

注意:这只是最简单的示例,没有任何错误处理或检查余额是否足以提取等。这只是为了演示目的而不用于实际应用。 通过封装,我立即知道:
  • accBalance 是一个私有字段,无法在类外部访问

  • 我只能检索 balance() 而不能在 Account 类的实例上明确设置它。

  • 我可以从帐户中deposit()withdraw() 钱(公开可访问的方法)。


在您的标准模块(module1)中,即使使用智能感知,也会列出 .Balance,这就是您的库/类用户需要担心的全部内容。

现在有一个标准编码模块来测试两个类(Module1)。

Sub Main()

    Dim myAccount As Account
    Set myAccount = New Account

    Debug.Print "Starting Balance: " & myAccount.Balance

    myAccount.Deposit (2000)
    Debug.Print "Deposited: 2000"

    myAccount.WithDraw (250)
    Debug.Print "Withdrew: 250"

    Debug.Print "Ending Balance: " & myAccount.Balance

    ' can't set balance
    ' myAccount.Balance = 999999999999999999999999
End Sub

如果你想了解VBA面向对象编程的入门知识,我可以推荐以下内容:


3
你可能仍然希望使用 LetGet 进行错误检查等封装。除非你出于严格的性能原因这样做(在这种情况下,最好使用 C++ 制作 DLL 然后引用它),否则更好的做法是保留通过错误检查或条件响应以后增强或改进类功能的选项。但是这是非常详细的解释,所以给个赞 +1。 - hnk
3
正如hnk指出的那样,仍然有使用“Let”和“Get”的有效理由,只是为了在否则是私有变量的情况下允许错误检查。所以我不会说OP的代码是错误的,只是有点不必要/非最优。对我来说,使用带有get和let的私有变量似乎是一个很好的实践,尽管我的学术背景是C++/C#,这可能只是习惯力量。 - Aiken
感谢 @Aiken 和 hnk,根据你们的有效观察更新了答案。 - user2140173
属性不仅限于类模块,也可以在标准代码模块中使用! - ChrisB

9

属性允许外部访问,就像属性是一个公共字段一样,同时允许类保持对数据的控制。

Get属性可以计算类中实际不存在的“变量”。例如,一个质量Get属性可能返回密度乘以体积的乘积。

Private density as Double
Private volume as Double
Private potentialEnergy

Public Property Get mass() As Double
   mass = density*volume
End Property 'Property Get mass

一个Let属性可以检查有效性,例如不接受负数体积。或者它可以保持对象的字段属性同步:

Public Property Let density(rho as Double)
   if rho > 0 then
      density = rho
      potentialEnergy = density * volume * gravity * height
End Property 'Property Get mass

通过省略Let或Get属性,您还可以将属性设置为只读(或只写 -- 不常用)。

除了在性能上稍微降低一点之外,对于任何允许公共访问的字段,从一开始就使用属性是一个好习惯,即使这些属性最初很简单,也有助于将来修改类。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接