VBA - CallByName不会接受变体参数 [英] VBA - CallByName won't accept variant arguments
问题描述
CallByName MobClass,TargetData,vbLet,(Value)
可能是删除,因为它不再相关和可能的重复。
我花了很长时间试图找出我使用CallByName的方式有什么问题。我终于意识到,如果输入不是与它的调用或其硬编码的输入参数完全相同的类型,那么它的第四个参数(Args)将引发类型不匹配。
(我甚至不知道如何,或者为什么,它自从 VarType(Variant / Integer)= VarType(Integer)
)
所以我需要一种方法让它接受变量输入或将变量从 Variant / Integer
转换为整数
(或创建一个新的变量)没有一个巨大的选择案例。
编辑:所以我的问题不清楚,所以我会解释它更详细。我有一堆我想循环访问的类,并调用 当它被初始化为<$时,问题是 Let 属性。我的简化设置是:
。唯一一次,我可以让它不抛出类型不匹配异常是当我初始化
pre $ Dim AllClasses as Collection
Sub SetAll(TargetProperty as String,Value as Variant)
对于AllClasses中的每个ClassX
CallByName ClassX,TargetProperty,vbLet,Value
Next ClassX
End Sub
Value
C $ C>变体值
作为属性想要的完全相同的类型,但我不能这样做,因为编辑2:我会问关于整个问题的另一个问题,因为没有人似乎知道很多关于 CallByName
编辑3:以下是我们到目前为止的摘要:
CallByName
的第四个参数(Args)在尝试调用时抛出类型不匹配> Let
类的属性。只有当试图分配的值存储在 Variant
数据类型中时,才会发生这种情况。 如果变量初始化为相同类型的让属性期望或者如果该值被硬编码到参数中,那么它可以很好地工作。
让属性可以自行工作。它接受
Variant
数据类型就好。
问题在于你通过引用传递属性参数而不是但不能将引用传递给其他数据类型(variant - > long),因为类型不匹配,并且无法转换,因为这也会更改调用方中的数据类型。通过使用括号,您强制参数被值传递,它可以被转换为类型 Long
。
您可以通过在属性字母中使用
而不是 ByVal
来避免此情况 ByRef
(如果未设置,隐式使用什么)。你知道通过引用一个变量,属性中所做的更改也会更改调用者的值?
示例:
类PassExample
'Save as class module PassExample
Public Property让PropByVal(ByVal NewVal As Long)
NewVal = 1
End Property
Public Property让PropByRef(ByRef NewVal As Long)
NewVal = 1
End Property
使用test子模块:
'save作为标准模块
Sub test()
Dim v As Variant
v = 0
Dim ExampleInstance As New PassExample
CallByName ExampleInstance, PropByVal,VbLet,v'这个工程
CallByName ExampleInstance,PropByRef,VbLet,v'类型不匹配
CallByName ExampleInstance,PropByRef,VbLet,(v)'This as the ByRef is changed to byval
Debug.Print v'显示0,而不是1,因为它应该是引用
CallByName ExampleInstance,PropByRef,VbLet,CVar(v)它传递了一个无法被引用的函数结果
End Sub
感谢Rory和chris neilsen提供解决方案!
Solution: Just put brackets around Value in the CallByName statement to force evaluation of it.
Ex. CallByName MobClass, TargetData, vbLet, (Value)
Credit goes to Rory from the other post, which I will probably be deleting since it is no longer relevant and a possible duplicate.
I've spent a long time trying to figure out what was wrong with how I was using CallByName. I finally realized that its fourth argument (Args) will throw a type mismatch if the input is not either EXACTLY the same type as the input argument of what its calling or its hard-coded in.
(I don't even understand how, or why, it does this since VarType(Variant/Integer) = VarType(Integer)
)
So I either need a way to make it accept variant inputs or convert variables from Variant/Integer
to Integer
(or create a new variable) without a giant select case.
Edit: So my question wasn't clear so I'll explain it in more detail. I have a bunch of classes that I want to cycle through and call the Let
property on. My simplified setup is:
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
The problem is Value
when it is initialized as Variant
. The only time I can get it to not throw a type mismatch exception is when I initialize Value
as the exact same type that the property wants, but I can't do that since the data types in the class vary.
Edit 2: I'm going to ask another question about the whole problem since no one seems to know much about CallByName
Edit 3: Here's a summary of what we have so far:
CallByName
's fourth argument (Args) throws a type mismatch when trying to call theLet
property on a class.This only happens when the value trying to be assigned is stored in a
Variant
data type. It works perfectly if the variable is initialized to the same type theLet
property is expecting OR if the value is hard-coded into the argument.The
Let
property works fine on its own. It acceptsVariant
data types just fine.My question is: Is there a way to stop this exception? I'm creating another post about other possible solutions to my overall problem.
The Problem is that you pass the properties-arguments by reference not by value, but you can't pass a reference to a different datatype (variant -> long) as the types don't match and it can't be converted as this would change the data type in the caller too. By using brackets, you force the argument to be passed by value and it can be casted as typeLong
.
You can avoid this by using ByVal
in theProperty Letter
instead ofByRef
(what is implicit used if not set). You are aware that by referencing a variable, changes made in the property change the callers value too?
Example:
Class PassExample
'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
Module with test sub:
'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
Thanks to Rory and chris neilsen for providing the solution!
这篇关于VBA - CallByName不会接受变体参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!