2010-04-10 74 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 

問題解決了大家。