2010-04-10 41 views
7

我无法让VBA的Evaluate()函数只执行一次;它似乎总是运行两次。例如,考虑下面的简单例子。如果我们运行RunEval()子程序,它会调用EvalTest()函数两次。这可以通过在即时窗口中打印的两个不同的随机数来看到。如果我们使用Evaluate而不是函数调用另一个子例程,行为将是相同的。有人可以解释我如何得到Evaluate执行一次目标函数而不是两次?谢谢。停止VBA从调用目标函数两次进行评估

Sub RunEval() 
    Evaluate "EvalTest()" 
End Sub 

Public Function EvalTest() 
    Debug.Print Rnd() 
End Function 

回答

7

此错误似乎只发生在UDF中,而不是内置函数。 您可以通过添加一个表达式绕过它:

Sub RunEval() 
    ActiveSheet.Evaluate "0+EvalTest()" 
End Sub 

但也有许多与评估其他限制,记录在这里 http://www.decisionmodels.com/calcsecretsh.htm

+0

它被认为是一个错误,或仅仅是无证的行为? – jtolle 2010-04-14 15:05:32

+0

我认为它是一个bug ... – 2010-04-15 09:53:00

+0

用括号语法调用函数(例如'[EvalTest]')实现相同的结果 – 2013-07-04 15:55:09

1

我做了快速搜索,发现其他人也报告了类似的行为和其他奇怪的错误与Application.Evaluate(见KB823604this)。至少从Excel 2002开始,微软的名单上这个数字可能并不高。这篇知识库文章给出了一种可能适用于您的案例的解决方法 - 将表达式在工作表中进行评估,然后从中获取值如下所示:

Sub RunEval() 
    Dim d As Double 

    Range("A1").Formula = "=EvalTest()" 
    d = Range("A1").Value 
    Range("A1").Clear 
    Debug.Print d 
End Sub 

Public Function EvalTest() As Double 
    Dim d As Double 
    d = Rnd() 
    Debug.Print d 
    EvalTest = d + 1 
End Function 

我修改了你的例子,也返回了函数中的随机值。这将再次打印该值,但添加了该值,因此第二次打印来自第一个子例程。您可以编写一个支持例程来为任何表达式执行此操作。

+0

谢谢凯文,太糟糕了,这还没有解决,但我很高兴有一个解决方法。 – Abiel 2010-04-10 17:27:28

1

我不知道一种方法来阻止它,但你至少可以在大部分时间识别它发生的情况。如果你的计算耗时或者有不希望发生两次的副作用,并且想要将其短路,那么这可能很有用。 (编辑:查尔斯威廉姆斯实际上有一个答案,你的具体问题。当你不知道什么样的数据类型,你可能会得到回报,或者当你期望得到像数组或类似的东西时,我的答案仍然可以是有用的范围)。

如果在调用Application.Evaluate的结果调用的例程中使用Application.Caller属性,则会看到其中一个调用看起来来自实际范围的左上角单元格Evaluate调用来自于,并且来自范围所在工作表的单元$ A $ 1。如果您从即时窗口呼叫Application.Evaluate,就像调用示例Sub一样,一次调用看起来来自当前选定范围的左上方单元格,另一个来自当前工作表的单元格$ A $ 1。我很确定这是第一次在两种情况下都是$ A $ 1的通话。 (我测试,如果它很重要。)

但是,只有一个值,将永远不会从Application.Evaluate返回。我很确定这是第二次评估的结果。 (我测试过。)

显然,这不会从实际单元格$ A $ 1的呼叫工作。

(至于我,我很想知道为什么双重评价发生了,我也很想知道为什么评价者在所有暴露的任何人。?)

编辑:我问StackOverflow上这里:Why is Excel's 'Evaluate' method a general expression evaluator?

我希望这可以帮助,但它并不直接回答你的问题。

1

我面临同样的问题,调查后,我发现,函数调用两次,因为我有下拉列表和用户定义的函数中使用的值。

由代码波纹管周围工作,把代码中的ThisWorkbook

私人小组Workbook_Open() “设置计算为手动停止计算当下拉列表updeated和再次计算用于UDF

 Application.Calculation = xlCalculationManual 

结束子

私人小组Workbook_SheetChange(BYVAL SH作为对象,_ BYVAL源作为范围)

“calculte只有当纸张改变

Calculate 

末次

-1

看有没有解决这个问题,正确的方法后,我解决它由以下:

Dim RunEval as boolean 

Sub RunEval() 
    RunEval = True 
    Evaluate "EvalTest()" 
End Sub 

Public Function EvalTest() 
    if RunEval = true then 
    Debug.Print Rnd() 
    RunEval = False 
    end if 
End Function 

问题解决了大家。