2010-09-27 103 views
3

爲什麼這個C#代碼不能編譯?爲什麼這個C#代碼不能編譯?

public static Dictionary<short, MemoryBuffer> GetBulkCustom(int bufferId, 
    int startSecond,out int chunksize, out int bardatetime) 
{ 
    //const string _functionName = "GetNextBulkWatchData"; 

    UserSeriesCard currentCard = GetUserSeriesCard(bufferId); 

    Dictionary<short, MemoryBuffer> result = null; 

    while (currentCard.CurrentSecond <= startSecond) 
     result = GetBulk(bufferId, out chunksize, out bardatetime); 

    if (result == null) 
    { 
     result = currentCard.UserBuffer; 
     chunksize = currentCard.ChunkSize; 
     bardatetime = currentCard.CurrentBarDateTime; 
    } 
    return result; 
} 

錯誤:

The out parameter 'bardatetime' must be assigned to before control leaves the current method 
The out parameter 'chunksize' must be assigned to before control leaves the current method 

我想不出哪裏bardatetime和CHUNKSIZE最終將未分配的情況..

編輯。我通過將代碼調整爲邏輯等效的代碼來解決此錯誤。老實說,我想避免多個assigments。

public static Dictionary<short, MemoryBuffer> GetBulkCustom(int bufferId, int startSecond,out int chunksize, out int bardatetime) 
    { 
     const string _functionName = "GetNextBulkWatchData"; 

     UserSeriesCard currentCard = GetUserSeriesCard(bufferId); 

     Dictionary<short, MemoryBuffer> result = null; 
     chunksize = currentCard.ChunkSize; 
     bardatetime = currentCard.CurrentBarDateTime; 

     while (currentCard.CurrentSecond <= startSecond) 
      result = GetBulk(bufferId, out chunksize, out bardatetime); 

     if (result == null) 
      result = currentCard.UserBuffer; 

     return result; 
    } 

回答

18

如果沒有輸入while循環和「if語句」主體,則不會分配輸出參數。

這可能是邏輯上知道這些代碼路徑將始終輸入的情況。 編譯器不知道。編譯器認爲可以輸入或跳過每個具有非恆定條件的「if」和「while」。

編譯器在這種情況下可以做更復雜的流分析。分析結果是「在'if'之前,結果是null或非null;如果它是null,那麼'if'主體會分配out參數,如果它不是null,那麼唯一可能發生的情況是'而'body分配了out參數,因此out參數被分配。「

這種分析的水平肯定是可以的,但在規範中描述的現有流程分析算法有一些很好的特性,即它是容易理解容易實現通常準確只給出了誤報,不漏報

+0

感謝Eric。你明白我的意思。簡單點 – mustafabar 2010-09-27 14:08:54

+6

我剛剛發現我正在和編譯器自己說話:D – mustafabar 2010-09-27 14:19:47

5

您的out參數沒有在所有代碼路徑中設置。如果你跳過依賴於和while (currentCard.CurrentSecond <= startSecond)if (result = null)的代碼段,那麼你必須對它們進行一些合理的默認賦值。

您可能知道while循環將至少執行一次,但編譯器不知道這一點。在這種情況下,您可以用do {//logic} while (//condition);替代替換該循環。

如果你不能這樣做,那麼這個構造應該使編譯器能夠檢測out變量的確定性設置。

if (currentCard.CurrentSecond <= startSecond) 
{ 
    while (currentCard.CurrentSecond <= startSecond) 
    { 
    result = GetBulk(bufferId, out chunksize, out bardatetime); 
    } 
} 
else 
{ 
    result = null; 
} 
+0

我知道一個事實,即如果while循環根本沒有執行,結果將最終爲'null',並且在下一個批處理器應該在下一個批處理中分配 – mustafabar 2010-09-27 13:58:18

+0

@Mustafa - 請參閱編輯代碼 – 2010-09-27 14:06:00

3
if currentCard.CurrentSecond > startSecond 

if result is null 

他們OUT參數,將不會分配。

你可以做這樣的事情:一個具有預

public static Dictionary<short, MemoryBuffer> GetBulkCustom(int bufferId, int startSecond,out int chunksize, out int bardatetime) 
{ 
    //const string _functionName = "GetNextBulkWatchData"; 


    UserSeriesCard currentCard = GetUserSeriesCard(bufferId); 

    Dictionary<short, MemoryBuffer> result = null; 

    // initialize with a -1 
    bardatetime = -1; 
    chunksize = -1; 

    while (currentCard.CurrentSecond <= startSecond) 
     result = GetBulk(bufferId, out chunksize, out bardatetime); 

    if (result == null) 
    { 
     result = currentCard.UserBuffer; 
     chunksize = currentCard.ChunkSize; 
     bardatetime = currentCard.CurrentBarDateTime; 
    } 

    return result; 
} 
+0

當然調用者應該知道如何處理-1這樣的值(例如,如果代碼「總是」成功地爲變量賦予實際值,那麼應該明確地測試該可能性)。我已經讓代碼運行好幾個月,直到使它使用我忘記測試的默認值。很有意思。 :) – MetalMikester 2010-09-27 14:00:30

+0

@MetalMikester,當然他們應該檢查處理中的初始化值,實現-1將是一個無效值。無論哪種方式,他都必須確保在退出之前將值分配給out params。這只是一種方法的例子。 – Gabe 2010-09-27 14:03:19

1

你可能無法想象,那些OUT參數,將不進行設置,但只要編譯器知道它是可能的(憑藉你檢查循環)以便控制在沒有設置這些參數的情況下退出。

2

兩種情況CHUNKSIZE和bardatetime分配的地方是某種形式的控制語句(while或IF),該編譯器無法知道里面如果這些部分會輸入或不輸入即

因此,就編譯器而言,對於這兩個輸出參數,沒有保證賦值。

1

如果result爲空,bardatetime將永遠不會被分配。在方法返回之前,必須設置聲明爲out的參數。只需將它初始化爲方法開始時的默認值,它應該可以正常工作。

0

如果currentCard.CardSecond < = startSecond while循環將不運行,結果將爲空,並且值將永遠不會設置。編譯器如何知道.CardSecond和startSecond會是什麼?

0

您可以嘗試用do {} while() - 循環替換while(){}循環。在這種情況下,分配將得到保證。

0

因爲對於方法中的編譯器,就像本地變量一樣,輸出參數最初被認爲是未分配的,並且在使用它的值之前必須明確分配,現在檢查您的實現GetBulk

0

在輸入函數時對它們進行初始化。

0

只是想指出,使用ReSharper,插件本身會突出顯示此代碼有什麼問題。