简体   繁体   English

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

[英]CallByName Unexpected results if argument is Variant array set to cell range

I have been using CallByName in a particular application and getting results which I cannot explain. 我一直在特定的应用程序中使用CallByName并得到我无法解释的结果。 They are reproducible on a simple test with the following conditions 它们在具有以下条件的简单测试中是可再现的

  • The property of the class object is of Type Double 类对象的属性是Type Double
  • The value being added (Let) comes from a variant array that has been set to a multiple cell range 添加的值(Let)来自已设置为多个单元格范围的变体数组

I would appreciate an explanation for this behavior. 我很感激这种行为的解释。 The following code should reproduce it (at least in Excel 2007 / Windows 7) 以下代码应该重现它(至少在Excel 2007 / Windows 7中)

Worksheet Cell A1 contains 5.8 工作表单元格A1包含5.8

A2 contains 1.3 and the rest of the cells in column A are blank. A2含有1.3 ,A列中的其余细胞是空白的。

Class Module (class1) 课程模块 (class1)

Private pMyData

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

Regular Module 常规模块

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

Note the 2nd debug.print line shows that the value stored in class1.MyData is 312080296 and not 5.8. 注意第二个debug.print行显示存储在class1.MyData中的值是312080296而不是5.8。

Same thing here. 这里也是一样的。 Getting 145842640. If it helps you don't have to use CallByName. 获取145842640.如果它有帮助您不必使用CallByName。 Using the below line worked for me to set it correctly to 5.8. 使用以下行可以帮我将其正确设置为5.8。

class1.MyData = W(1, 1)

Might also help to declare pMyData a double, and also in Let/Get statments. 可能还有助于将pMyData声明为double,以及Let / Get语句。 Then you'll get an error when attempting to assign, like the first V(1,1), which will force you to explicitly declare the conversion, which appears to be a good thing (or necessary even) in this situation. 然后你会在尝试分配时遇到错误,比如第一个V(1,1),它会强制你明确地声明转换,这在这种情况下似乎是一件好事(或者说是必要的)。

Couldn't find a good quick reason why it is doing that though, or what the conversion is actually doing. 无法找到一个很好的快速原因,为什么它正在这样做,或转换实际上在做什么。 Hopefully someone knows, I'm curious now. 希望有人知道,我现在很好奇。

EDIT - It would appear that CallByName is actually passing the address of W(1,1) to the Let statement. 编辑 - 看起来CallByName实际上是将W(1,1)的地址传递给Let语句。 (Passing the value of the pointer, in other words.) It would appear converting via CDbl dereferences the pointer, getting the value, which is why it works with the explicit conversion. (换句话说,传递指针的值。)它似乎通过CDbl解引用转换指针,获取值,这就是它与显式转换一起工作的原因。 (Or so I think anyway.) (不管怎么说,我想。)

Try adding this function: 尝试添加此功能:

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

Then do a debug.pring for W(1,1), and a debug.print for VarPtr(W(1,1)). 然后为W(1,1)执行debug.pring,为VarPtr执行debug.print(W(1,1))。 I found that the myData and the VarPtr value for W(1,1) were one and the same. 我发现W(1,1)的myData和VarPtr值是同一个。 I assume this is part of the behavior of the CallByName function, as far as passing the address, not the value, but I don't have time to research further. 我认为这是CallByName函数行为的一部分,只要传递地址,而不是值,但我没有时间进一步研究。 Hope that helps. 希望有所帮助。

I got this line to work correctly, 我让这条线正常工作,

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

Only thing I can think of is CallByName expects Args() as a Variant , and W(1,1) cannot be implicitly cast..(for some reason) 我唯一能想到的是CallByName期望Args()作为VariantW(1,1)不能被隐式转换..(由于某种原因)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM