Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/excel/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Excel 如果参数为变量数组并设置为单元格范围,则CallByName会出现意外结果_Excel_Vba - Fatal编程技术网

Excel 如果参数为变量数组并设置为单元格范围,则CallByName会出现意外结果

Excel 如果参数为变量数组并设置为单元格范围,则CallByName会出现意外结果,excel,vba,Excel,Vba,我在一个特定的应用程序中使用了CallByName,得到了无法解释的结果。在以下条件下,可通过简单试验进行再现 类对象的属性是Double类型 正在添加的值(Let)来自已设置为多单元格范围的变量数组 我希望能对这种行为做出解释。以下代码应复制它(至少在Excel 2007/Windows 7中) 工作表单元格A1包含5.8 A2包含1.3,列A中的其余单元格为空白 班级模块(1级) 常规模块 Option Explicit Sub foo() Dim class1 As class

我在一个特定的应用程序中使用了CallByName,得到了无法解释的结果。在以下条件下,可通过简单试验进行再现

  • 类对象的属性是Double类型
  • 正在添加的值(Let)来自已设置为多单元格范围的变量数组
我希望能对这种行为做出解释。以下代码应复制它(至少在Excel 2007/Windows 7中)

工作表单元格A1包含5.8

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

班级模块(1级)

常规模块

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
选项显式
副秘书长()
将类别1视为类别1
尺寸V(1到2,1到1)作为变型
V(1,1)=[a1]
V(2,1)=[a2]
设置类别1=新类别1
CallByName class1,“MyData”,VbLet,V(1,1)

在这里打印V(1,1),class1.MyData'同样的东西。获取145842640。如果有帮助的话,你不必使用CallByName。使用下面的一行可以将其正确设置为5.8

class1.MyData = W(1, 1)
也可能有助于将pMyData声明为double,以及在Let/Get stations中。然后,在尝试赋值时会出现错误,如第一个V(1,1),这将迫使您显式声明转换,在这种情况下,这似乎是一件好事(甚至是必要的)

但是,找不到一个很好的快速理由来解释为什么要这样做,或者转换实际上在做什么。希望有人知道,我现在很好奇

EDIT-似乎CallByName实际上正在将W(1,1)的地址传递给Let语句。(换句话说,传递指针的值。)通过CDbl进行转换似乎会取消对指针的引用,从而获得值,这就是它使用显式转换的原因。(至少我是这么认为的。)

尝试添加此功能:

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类1,“我的数据”,VbLet,CVar(W(1,1))


我唯一能想到的是
CallByName
期望
Args()
作为
变量
,并且
W(1,1)
不能隐式强制转换..(出于某种原因)

我不确定这是否有帮助,但我运行了您发布的测试,每次都为第二个debug.print行获取不同的数字。没有一个是312080296,但它们的震级相同。“对不起,我还没弄清楚是什么问题。”工程师谢谢。是的,每次运行我也会得到不同的值。我想如果我们能解释第一个值,我们就能理解其他值。我注意到关于Args()是一个变量的语句。但这似乎与CDbl(W(1,1))的事实不符,CDbl(W(1,1))显然返回了一个双精度,工作正常。@GeneSkuratovsky是的,同意。虽然我认为欧普确实说过,公平地说,这不是他喜欢的做事方式:-)。我以前从未见过这种功能@GeneSkuratovsky这并不是MS Help第一次不完整或具有误导性。显然,参数可以不是Variant(Array)。@GeneSkuratovsky这是我的第一个想法,但当我看到VBA帮助的其他部分引用了该数据类型时,单词Array周围的括号不包括在内,“帮助”中的示例显然没有使用变体数组。@GeneSkuratovsky我认为这一讨论现在不在StackOverflow的范围之内,因此尽管我不同意你的观点,但我不会继续深入讨论。由于性能受到影响,我不希望一般使用CallByName。但是我正在做的工作的性质使得编写和调试这个替代方案变得非常笨拙。谢谢您关于VarPtr的提示。一旦我找到了在VBA6中使用的正确声明,我发现了与您所注意到的相同的行为。在这个看似非常特殊的实例中,CallByName传递的是引用而不是数据,这似乎很奇怪。但是,感谢您提供指向指针的指针:-)
Public Declare PtrSafe Function VarPtrArray Lib "VBE7" Alias _
    "VarPtr" (Var() As Any) As LongPtr