3

为什么此 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 最终未分配的情况。

编辑. 我通过将代码调整为逻辑上等效的代码来修复此错误。老实说,我想避免多次分配。

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;
    }
4

11 回答 11

18

如果从未输入过 while 循环和“if 语句”主体,则不会分配 out 参数。

从逻辑上讲,可能知道将始终输入这些代码路径。编译器不知道这一点。编译器认为可以输入或跳过每个具有非恒定条件的“if”和“while”。

在这种情况下,编译器可以进行更复杂的流分析。分析是“在'if'之前,结果要么为null,要么不为null;如果为null,则'if'主体分配out参数。如果它不为null,那么唯一可能发生的方法是' while'body 分配了 out 参数,因此分配了 out 参数。”

这种级别的分析当然是可能的,但是规范中描述的现有流分析算法有一些很好的特性,即它速度快易于理解易于实现通常准确只给出误报,而不是误报

于 2010-09-27T13:51:18.807 回答
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;
}
于 2010-09-27T13:50:27.997 回答
3
if currentCard.CurrentSecond > startSecond 

if result is null

他们将不会分配参数。

你可以这样做:

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;
}
于 2010-09-27T13:51:13.613 回答
2

分配 chunksize 和 bardatetime 的两个地方都在某种控制语句(while 或 if)中,编译器无法知道这些部分是否会被输入或记录。

因此,就编译器所知,对于这两个输出参数,没有保证赋值。

于 2010-09-27T13:51:20.803 回答
1

您可能不会想到不会设置那些 out 参数,但据编译器所知,在不设置这些参数的情况下控制退出是可能的(由于您有一个预检查循环)。

于 2010-09-27T13:51:17.510 回答
1

如果result为 null,bardatetime则永远不会被分配。声明为的参数out必须在方法返回之前设置。只需在方法开始时将其初始化为默认值,它应该可以正常工作。

于 2010-09-27T13:51:24.170 回答
0

如果 currentCard.CardSecond <= startSecond while 循环不会运行,结果将为 null 并且值将永远不会被设置。编译器如何知道 .CardSecond 和 startSecond 是什么?

于 2010-09-27T13:51:31.340 回答
0

您可以尝试用 do{}while() 循环替换 while(){} 循环。在这种情况下,分配将得到保证。

于 2010-09-27T13:53:46.883 回答
0

因为对于方法中的编译器,就像局部变量一样,输出参数最初被认为是未分配的,并且必须在使用它的值之前明确分配现在检查你的实现GetBulk

于 2010-09-27T13:54:16.773 回答
0

输入函数时初始化它们。

于 2010-09-27T13:55:28.803 回答
0

只是想指出,使用ReSharper插件本身会突出显示此代码的问题。

于 2010-09-27T13:58:41.980 回答