2010-09-27 97 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,插件本身会突出显示此代码有什么问题。