Почему этот код C # не компилируется? - PullRequest
3 голосов
/ 27 сентября 2010

Почему этот код 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;
    }

Ответы [ 11 ]

18 голосов
/ 27 сентября 2010

Если циклы while и «if Statement» никогда не вводятся, тогда выходные параметры не назначаются.

Возможно, логически you знает, что эти пути кода будутвсегда быть введенным. компилятор этого не знает.Компилятор считает, что каждое «если» и «время», которое имеет непостоянное условие, может быть введено или пропущено.

Компилятор в этом случае может выполнить более сложный анализ потока.Анализ «перед« если », результат либо нулевой, либо не нулевой; если он нулевой, то тело« если »назначает выходные параметры. Если это не ноль, то единственный способ, который мог бы произойти, это еслиВ то время как 'body назначил параметры out, следовательно, параметры out назначены. "

Этот уровень анализа, безусловно, возможен, но существующий алгоритм анализа потока, описанный в спецификации, имеет некоторые приятные свойства, а именно, что он быстро , легко понять , легко реализовать , обычно точно и дает только ложные срабатывания, а не ложные отрицания .

5 голосов
/ 27 сентября 2010

Ваши параметры 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;
}
3 голосов
/ 27 сентября 2010
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;
}
2 голосов
/ 27 сентября 2010

Оба места, где назначаются chunksize и bardatetime, находятся внутри некоторого управляющего оператора (во время или если), который компилятор не может знать, будут ли введены эти разделы или указано.

Как таковое, насколько известно компилятору, не существует гарантированного назначения этих двух выходных параметров.

1 голос
/ 27 сентября 2010

Если result равно нулю, bardatetime никогда не будет назначено. Параметр, объявленный как out, должен быть установлен до возврата метода. Просто инициализируйте его значением по умолчанию в начале метода, оно должно работать нормально.

1 голос
/ 27 сентября 2010

Вы не можете себе представить, что эти выходные параметры не будут установлены, но насколько компилятор знает, что возможно (благодаря тому, что у вас есть цикл предварительной проверки) для выхода управления без этих параметров.

0 голосов
/ 27 сентября 2010

Просто хотел отметить, что при использовании ReSharper сам плагин подскажет, что не так с этим кодом.

0 голосов
/ 27 сентября 2010

Инициализируйте их при входе в функцию.

0 голосов
/ 27 сентября 2010

Поскольку для компилятора в методе, как и в локальной переменной, выходной параметр изначально считается неназначенным и должен быть обязательно назначен, прежде чем его значение будет использовано, теперь проверьте вашу реализацию GetBulk.

0 голосов
/ 27 сентября 2010

Вы можете попробовать заменить цикл while () {} на цикл do {} while () -. В этом случае назначение будет гарантировано.

...