【问题标题】:VBA - CallByName won't accept variant argumentsVBA - CallByName 不接受变体参数
【发布时间】:2018-03-13 21:36:16
【问题描述】:

解决方案:只需在 CallByName 语句中的 Value 周围加上方括号以强制对其进行评估。

例如。 CallByName MobClass, TargetData, vbLet, (Value)

Rory 来自另一个帖子,我可能会删除它,因为它不再相关并且可能重复。

我花了很长时间试图弄清楚我使用 CallByName 的方式出了什么问题。我终于意识到,如果输入与其调用或硬编码的输入参数的类型不完全相同,它的第四个参数 (Args) 将引发类型不匹配。

(我什至不明白自从VarType(Variant/Integer) = VarType(Integer) 以来它是如何或为什么这样做的)

所以我要么需要一种方法让它接受变体输入,要么将变量从 Variant/Integer 转换为 Integer(或创建一个新变量),而不需要巨大的选择案例。

编辑:所以我的问题不清楚,所以我会更详细地解释它。我有一堆类,我想循环并调用Let 属性。我的简化设置是:

Dim AllClasses as Collection 
Sub SetAll(TargetProperty as String, Value as Variant)

    For each ClassX in AllClasses

        CallByName ClassX, TargetProperty, vbLet, Value

    Next ClassX

End Sub 

问题是Value初始化为Variant。我唯一可以让它不引发类型不匹配异常的情况是,当我将 Value 初始化为属性所需的完全相同的类型时,但我不能这样做,因为类中的数据类型不同。

编辑 2:我要问另一个关于整个问题的问题,因为似乎没有人对 CallByName 了解很多

编辑 3:以下是我们目前所做的总结:

  • CallByName 的第四个参数 (Args) 在尝试调用类的 Let 属性时会引发类型不匹配。

  • 仅当尝试分配的值存储在 Variant 数据类型中时才会发生这种情况。如果将变量初始化为 Let 属性所期望的相同类型,或者将值硬编码到参数中,则它可以完美运行。

  • Let 属性可以单独工作。它接受Variant 数据类型就好了。

  • 我的问题是:有没有办法阻止此异常?我正在创建another post,以了解针对我的整体问题的其他可能解决方案。

【问题讨论】:

  • 你在没有开玩笑的情况下就跳到了重点。请问这个代码在哪里?
  • 如果您的按名称调用方法需要 Integer,您可以键入将变量转换为整数,例如 CallByName obj, "Test", VbMethod, CInt(v)
  • Cint(x) 也不起作用,它仍然会抛出异常。
  • 您的编辑有帮助,但距离minimal reproducible example 还很远。
  • 除了技术指导说 args() Optional: Variant (Array).

标签: vba excel function


【解决方案1】:

问题是您通过引用而不是通过值传递属性参数,但是您不能传递对不同数据类型(变体->长)的引用,因为类型不匹配并且不能转换,因为这也会改变调用者中的数据类型。通过使用括号,您可以将force the argument to be passed by value 转换为typeLong

您可以通过在Property Letter而不是ByRef中使用ByVal来避免这种情况(如果未设置则隐式使用)。您知道通过引用变量,对属性所做的更改也会更改调用者的值吗?

例子:

类通行证示例

'Save as class module PassExample
Public Property Let PropByVal(ByVal NewVal As Long)
NewVal = 1
End Property
Public Property Let PropByRef(ByRef NewVal As Long)
NewVal = 1
End Property 

带有测试子的模块:

'save as standard module
Sub test()
Dim v As Variant
v = 0

Dim ExampleInstance As New PassExample

CallByName ExampleInstance, "PropByVal", VbLet, v 'this works
CallByName ExampleInstance, "PropByRef", VbLet, v 'type mismatch
CallByName ExampleInstance, "PropByRef", VbLet, (v) 'this works as ByRef is changed to byval
Debug.Print v ' shows 0, not 1 as it should be if referenced

CallByName ExampleInstance, "PropByRef", VbLet, CVar(v) ' works too as it passes a function-result that can't be referenced

End Sub

感谢 Rory 和 chris neilsen 提供的解决方案!

【讨论】:

  • 这是有道理的,抱歉我在问这个问题之前没有想到这一点。我一直在用 C++ 编程,它的默认值是按值传递,所以我从来没有真正想过它。
  • @LeoSteeves 不需要借口,这对我来说是个好问题。在这方面学到了很多东西。。只是一个愿望;)用你的类属性的例子改进你的问题,以便为其他人解决问题。当然,你会得到更多的选票,因为主题本身并不常见,我无法为我编写代码;)。对显示名称属性类的反馈也很好,因为不清楚这是否对您有帮助。
  • 查看this answer 了解使用类的替代方法
猜你喜欢
  • 2016-05-29
  • 1970-01-01
  • 2016-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-16
  • 1970-01-01
相关资源
最近更新 更多