«Использование неназначенной переменной» - обходные пути? - PullRequest
4 голосов
/ 07 июля 2011

Теперь я давно знаю и привык к этому поведению в C #, и в целом мне это нравится.Но иногда компилятор просто недостаточно умен.

У меня есть небольшой фрагмент кода, где сейчас мой обходной путь не является большой проблемой, но это может быть в подобных случаях.

        bool gap=false;
        DateTime start; // = new DateTime();
        for (int i = 0; i < totaldays; i++)
        {
            if (gap)
            {
                if (list[i])
                {
                    var whgap = new WorkHistoryGap();
                    whgap.From = start; //unassigned variable error
                    whgap.To = dtFrom.AddDays(i);
                    return whgap;
                }
            }
            else
            {
                gap = true;
                start = dtFrom.AddDays(i);
            }
        }

Проблема, с которой я сталкиваюсь, заключается в том, что если бы вам пришлось делать это с необнуляемой структурой, у которой не было конструктора по умолчанию?В любом случае можно было бы обойти это, если бы start не был простым объектом DateTime?

Ответы [ 5 ]

10 голосов
/ 07 июля 2011

иногда компилятор просто недостаточно умен

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

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

http://blogs.msdn.com/b/ericlippert/archive/2011/02/24/never-say-never-part-two.aspx

что если бы вам пришлось делать это с ненулевой структурой, у которой не было конструктора по умолчанию?

Такого животного нет. Все структуры, обнуляемые или нет, имеют конструктор по умолчанию.

Можно ли было бы обойти это, если бы start не был простым объектом DateTime?

Выражение default(T) дает вам значение по умолчанию для любого типа T. Вы всегда можете сказать

Foo f = default(Foo);

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

6 голосов
/ 07 июля 2011

Компилятор не может знать, что вы гарантированно установите DateTime из-за своей переменной gap.

Просто используйте

DateTime start = DateTime.Now;

и покончите с этим.

Редактировать Еще лучше, на второй взгляд через ваш код, использовать

DateTime start = dtFrom;
4 голосов
/ 07 июля 2011

В struct нет такого понятия, как конструктор по умолчанию.Попробуйте:

struct MyStruct {
    public MyStruct() {
        // doesn't work
    }
}

У вас может быть статический конструктор, но вы не можете определить конструктор по умолчанию для struct.Вот почему есть статический метод Create для стольких структур, и поэтому вы можете сказать new Point() вместо Point.Empty.

«Конструктор по умолчанию» любого struct всегда инициализирует все его поляк их значениям по умолчанию.Статическое поле Empty для определенных типов для удобства.Это фактически не имеет никакого значения в производительности, потому что это типы значений.

3 голосов
/ 07 июля 2011

Похоже, ваш bool gap и DateTime start - это одно и то же.Попробуйте рефакторинг так:

DateTime? gapStart = null ;
for (int i = 0; i < totaldays; i++)
{
    if ( gapStart.HasValue )
    {
        if (list[i])
        {
            var whgap  = new WorkHistoryGap();
            whgap.From = gapStart.Value ; //unassigned variable error
            whgap.To   = dtFrom.AddDays(i);
            return whgap;
        }
    }
    else
    {
        gapStart = dtFrom.AddDays(i);
    }
}

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

[далее отредактировано, чтобы отметить: вы устанавливаете разрыв в значение true и устанавливаете значение start в первый раз в цикле.Дальнейший рефакторинг к чему-то вроде этого:]

DateTime gapStart = dtFrom.AddDays( 0 );
for ( int i = 1 ; i < totaldays ; i++ )
{
  if ( list[i] )
  {
    var whgap  = new WorkHistoryGap();
    whgap.From = gapStart.Value; //unassigned variable error
    whgap.To = dtFrom.AddDays( i );
    return whgap;
  }
}
1 голос
/ 07 июля 2011

Почему вы пытаетесь обойти дизайн языка?Даже если компилятор может обработать весь ваш цикл заранее, что кажется слишком сложным со стороны компилятора, как он узнает, что исключения не могут быть выброшены в части вашего кода?Вы ДОЛЖНЫ присвоить значение start, потому что вы используете его позже в коде, возможно, до его (по вашему мнению) неизбежного присвоения.

...