Использование неназначенной локальной переменной? С#

У меня есть следующий код:

        double ticketPrice;
        LoadOperation loGetTickets = ticketClass.loadTickets();
        loGetTickets.Completed += (s, args) =>
        {
            foreach (Web.Ticket tt in ticketClass.getContext())
            {
                if (tt.bookingId == data.bookingId)
                {
                    pView.lblTicketAmount.Content = "£" + tt.ticketPrice;
                    MessageBox.Show("Price: " + tt.ticketPrice);
                    ticketPrice = Convert.ToDouble(tt.ticketPrice);
                    pView.lblTicketName.Content = tt.ticketName;
                    break;
                }
            }
        }; double subTotal = ticketPrice + ticketQuantity;

Когда я запускаю его, я получаю сообщение об ошибке: Использование неназначенной локальной переменной 'ticketPrice'

Как видите, ему присваивается значение из цикла.

Если я использую:

double ticketPrice = 0.0;

Ошибка исчезает, но затем значение остается равным 0.0, но я не понимаю, потому что окно сообщений появляется каждый раз и выводит значение, поэтому я бы предположил, что значение tt.ticketPrice заполняется ticketPrice

Может ли кто-нибудь помочь мне в этом вопросе.

Спасибо


person Sandeep Bansal    schedule 02.05.2011    source источник
comment
Я никогда не видел ошибки времени выполнения Использование неназначенной локальной переменной просто ошибка времени компиляции такого рода.   -  person Jared Updike    schedule 03.05.2011
comment
Это вопрос с подвохом? Присваивание идет после двух строк, в которых используется значение ticketPrice.   -  person    schedule 03.05.2011
comment
@Jon of All Trades: э-э, нет, tt.ticketPrice не имеет никакого отношения к ticketPrice (кроме похожих имен).   -  person rsenna    schedule 03.05.2011


Ответы (4)


Вы говорите, что значение ticketPrice остается равным нулю, но код не показывает место, где вы читаете значение переменной!

Такое поведение имело бы смысл, если бы оно использовалось в некотором коде, следующем за фрагментом, который вы опубликовали. Например.:

double ticketPrice;        
LoadOperation loGetTickets = ticketClass.loadTickets();        
loGetTickets.Completed += (s, args) =>  { 
  // Set value of 'ticketPrice'
  ticketPrice = ...
};

// Use the value of the variable
Console.WriteLine(ticketPrice); // (*)

Это не работает, потому что строка, помеченная как (*), на самом деле завершается до того, как значение переменной будет установлено в обработчике Completed. Чтобы заставить его работать, вам нужно переместить код, который использует переменную, в обработчик (после кода, который устанавливает значение переменной).

Тогда, конечно, объявлять переменную в методе не имеет смысла, потому что она будет использоваться только в теле лямбда-функции, так что у вас получится что-то вроде этого:

LoadOperation loGetTickets = ticketClass.loadTickets();        
loGetTickets.Completed += (s, args) =>  { 
  double ticketPrice;        
  // Set value of 'ticketPrice'
  ticketPrice = ...

  // Use the value of the variable
  Console.WriteLine(ticketPrice); // (*)
};

Я полагаю, что вы только что обнаружили болевые точки асинхронного программирования в C# 4 :-). Вот почему F# поддерживает асинхронные рабочие процессы (где вы можете писать один и тот же код без обработчиков событий) и почему разработчики C# думают о добавлении подобных вещей в C# в будущем.

person Tomas Petricek    schedule 02.05.2011
comment
ОК, я вас понимаю, так как запрос еще не закончил обработку, у него нет времени использовать tt.ticketPrice в ticketPrice до того, как код завершит выполнение? - person Sandeep Bansal; 03.05.2011
comment
Хорошо, все, что я сделал, это просто перенес вычисления в событие. Работает сейчас, но я думаю, я должен просто попытаться избежать этого. Спасибо за информацию! - person Sandeep Bansal; 03.05.2011
comment
@Sandeep: Да, именно в этом проблема. Не гарантируется, что обработчик завершится до того, как выполнение основного метода переместится на следующую строку (и использует ticketPrice). При запуске какой-либо асинхронной операции (для которой требуется обработчик) остальная часть вызывающего метода обычно не требует большого количества кода. - person Tomas Petricek; 03.05.2011

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

person Joshua    schedule 02.05.2011

Переместите оператор double ticketPrive; внутрь оператора foreach, и все будет хорошо.

person Richard Schneider    schedule 02.05.2011
comment
если он находится внутри foreach, возникает вопрос, зачем он вообще? - person BrokenGlass; 03.05.2011
comment
Его можно использовать только внутри лямбда-выражения, поэтому переместите его туда! - person Richard Schneider; 03.05.2011
comment
Это неправильно, его также можно использовать вне обработчика событий. Однако тогда, конечно, вам придется подождать, пока событие не произойдет. - person Guffa; 03.05.2011

Переменная присваивается, но это происходит позже.

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

Если вы попытаетесь использовать переменную немедленно, она не будет установлена. Вы не можете использовать переменную до тех пор, пока не произойдет событие. Самый простой способ сделать это — поместить код, использующий переменную, внутрь обработчика событий.

person Guffa    schedule 02.05.2011