【问题标题】:Changing a Type to a Class causes ByRef parameters to act ByVal将类型更改为类会导致 ByRef 参数执行 ByVal
【发布时间】:2018-01-12 22:34:37
【问题描述】:

我听说过将用户定义类型 (UDT) 更改为常规类的建议,以克服 UDT 的限制,例如无法将 For Each 与 UDT 一起使用。

我还听说过从常规 Class 更改为 UDT 的建议,以克服 Class 限制,您不能通过 BYREF 传递东西,例如...

'Function:
Public Function RemoveArticle (ByRef strMovieTitle As String)
    'Expected input is like "Terminator, The"
    strMovieTitle = Left(... 'removes the article.
End Function

这个电话很好用:

Dim strMovieTitle As String
strMovieTitle = "Terminator, The"
RemoveArticle strMovieTitle

但不是这个电话:

Dim objMovie As MovieClass
objMovie.strMovieTitle = "Terminator, The"
objMovie.strMovieGenre = "Sci-Fi"
InvertArticle objMovie.strMovieTitle

尽管 MovieClass 定义了

strMovieTitle As String

我不能将 RemoveArticle(以及每个类似的简单小函数)更改为采用 MovieClass 参数而不是 String 参数,因为还有其他 UDT 或类和字符串变量也需要使用 RemoveArticle。

如果我需要使用 For Each 并且我还需要通过 ByRef 怎么办? 类有没有办法解决参数问题?

(使用 Excel 2010。)

【问题讨论】:

  • 当您将对象的属性传递给方法(并且该属性的值不是对象本身)时,您只是传递了值的副本,而不是属性本身,而我'我不确定有没有简单的方法解决这个问题。 objMovie.strMovieTitle = RemoveArticle(objMovie.strMovieTitle) 可能是你能做的最好的了。
  • 您可能需要考虑将InvertArticleRemoveArticle 移动到MovieClass 内部。将所有相关的功能封装在类中使得审查和调试变得非常容易(特别是如果您有一段时间没有使用代码)并且objMovie.RemoveArticle 非常干净。
  • @npeirce:您可以使用DictionaryCollection 来存储MovieClass 对象。在那里,您可以使用 UDF 或一个名为 Movies 的类和这些函数(invertremove)...另外,您能否提供参考您提出的那些建议?据我所知,在一个类中可以用ByRef传递的参数定义方法(其实任何对象都可以传递ByRef).
  • @rellampec,我有很多使用字符串的函数,所以我无法真正更改所有这些函数。即使我这样做了,与电影无关的常规字符串变量使用它们也将无法访问或奇怪。也就是说,电影并不是唯一需要倒置或删除文章的东西。还有一些函数需要访问多个类型/类的内部变量。
  • @rellampec,我同意你的观点,“在一个类中,你可以定义带有通过 ByRef 传递的参数的方法”,但我说的有点不同:在类之外,你可以定义函数通过 ByRef 传递的参数,作为调用者,您可以将类对象的变量传递给该函数,例如,传递 objMovie.strMovieTitle 但在该函数中所做的任何更改都不会反映在下一行代码的 objMovie.strMovieTitle 中调用执行后。请参阅上面蒂姆威廉姆斯的评论,他说“你只是在传递一份副本”。这就是类的缺点。

标签: vba class pass-by-reference user-defined-types


【解决方案1】:

现在我明白你的担心了。

您根本无法采用这种方法来实现您的目标。正如蒂姆威廉姆斯在您的问题中评论的那样,您最好的选择是这样的:

Dim objMovie As MovieClass
Dim strMovieTitle As String
strMovieTitle = "Terminator, The"
objMovie.strMovieTitle = InvertArticle(strMovieTitle)

但是,我发现这仍然不能满足您的需要。

我的建议如下:

  • 使您的对象成为内部对象,目标属性Private 并使用Property LetProperty Get 公开它们。通过这种方式,您可以对 setget 上的属性进行所需的修改(从类内...而不是从类外修复)。

旁注,关于创建helper class(有人向您推荐):您可以将您广泛使用的所有功能加入一个类,例如RemoveArticle 或@ 987654327@。但是,每次您想使用它们时都需要创建一个实例对象,因此与我给您的建议不能很好地结合(如果您只想简化代码)。因此,像现在这样将它们放在Module 中就可以了。澄清一下:他们给你的那些建议与你的问题无关。

示例 A:set

在你的 MovieClass 类中,首先将 strMovieTitle 的所有实例重命名为 pStrMovieTitle 并将其添加到你的代码中:

Private pStrMovieTitle As String

Public Property Let strMovieTitle (strIn As String)
 pStrMovieTitle = InvertArticle(strIn)
End Property

Public Property Get strMovieTitle As String
 strMovieTitle = pStrMovieTitle
End Property

用法是这样的:

Dim objMovie As MovieClass
objMovie.strMovieTitle = "Terminator, The" ' the article position gets rectified on assignation
objMovie.strMovieGenre = "Sci-Fi"
'InvertArticle objMovie.strMovieTitle ' => you don't need to do this call

示例 B:get

保持原始字符串不变,并在获得属性值时应用您的helpers。这样,您始终保留原始字符串。但是,这种方法需要更多的返工,并且仅在您有很多方法可以在代码的不同部分使用 String 的情况下才值得。

Private pStrMovieTitleSource As String

Public Property Let strMovieTitle (strIn As String)
 pStrMovieTitleSource = Trim(strIn)
End Property

Public Property Get strMovieTitleSource () As String
 strMovieTitleSource = pStrMovieTitleSource
End Property

Public Property Get strMovieTitleRoot () As String
 strMovieTitleRoot = RemoveArticle(pStrMovieTitleSource)
End Property

Public Property Get strMovieTitle () As String
 strMovieTitle = InvertArticle(pStrMovieTitleSource)
End Property

希望对你有帮助

【讨论】:

  • 谢谢@rellampec 和大家。我可以接受“您根本无法采用这种方法来实现您的目标。” :) 我也非常感谢所有额外的信息和建议!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-10
  • 2019-04-11
  • 1970-01-01
  • 2014-01-26
  • 1970-01-01
  • 1970-01-01
  • 2015-02-15
相关资源
最近更新 更多