CallByName如果参数是将Variant数组设置为单元格范围,则会出现意外的结果

我一直在使用CallByName在一个特定的应用程序,并得到我无法解释的结果。 它们在以下条件下可通过简单的testing重现

  • 类对象的属性是typesDouble
  • 正在添加的值(Let)来自已设置为多个单元格范围的变体数组

我将不胜感激这种行为的解释。 下面的代码应该重现它(至less在Excel 2007 / Windows 7中)

工作表单元格A1包含5.8

A2包含1.3 ,列A中的其余单元格为空白。

类模块 (class1)

Private pMyData Public Property Get MyData() MyData = pMyData End Property Public Property Let MyData(Value) pMyData = Value End Property 

常规模块

 Option Explicit Sub foo() Dim class1 As class1 Dim V(1 To 2, 1 To 1) As Variant V(1, 1) = [a1] V(2, 1) = [a2] Set class1 = New class1 CallByName class1, "MyData", VbLet, V(1, 1) Debug.Print V(1, 1), class1.MyData ' <-- 5.8 5.8 Dim W As Variant W = Range("A1:A2") Set class1 = New class1 CallByName class1, "MyData", VbLet, W(1, 1) Debug.Print W(1, 1), class1.MyData ' <-- 5.8 312080296 CallByName class1, "MyData", VbLet, CDbl(W(1, 1)) Debug.Print W(1, 1), class1.MyData ' <-- 5.8 5.8 End Sub 

注意第二个debug.print行显示存储在class1.MyData中的值是312080296而不是5.8。

这里一样的东西。 获取145842640.如果有帮助,您不必使用CallByName。 使用下面的线为我工作正确地设置为5.8。

 class1.MyData = W(1, 1) 

也可能有助于声明pMyData一倍,并且也在Let / Get语句中。 然后,在尝试分配时会出现错误,就像第一个V(1,1)一样,这会迫使您明确地声明转换,在这种情况下这似乎是一件好事(甚至是必要的)。

找不到一个很好的理由说明为什么这样做,或者转换实际上在做什么。 希望有人知道,我现在好奇。

编辑 – 看来,CallByName实际上是W(1,1)的地址传递给Let语句。 (换句话说,传递指针的值。)它会出现通过CDbl解引用指针,获取值,这就是为什么它与显式转换工作。 (或者我认为无论如何。)

尝试添加这个function:

 Public Declare PtrSafe Function VarPtrArray Lib "VBE7" Alias _ "VarPtr" (Var() As Any) As LongPtr 

然后为W(1,1)做一个debug.pring,为VarPtr(W(1,1))做一个debug.print。 我发现W(1,1)的myData和VarPtr值是一样的。 我认为这是CallByName函数行为的一部分,只要传递地址,而不是值,但我没有时间进一步研究。 希望有所帮助。

我得到这个线路正常工作,

CallByName class1, "MyData", VbLet, CVar(W(1, 1))

只有我能想到的是CallByName期望Args()作为一个Variant ,而W(1,1)不能隐式转换..(出于某种原因)