Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
В этом нет ничего плохого. Компилятор по сути делает автоматически то, что вы назвали своей альтернативой. Он создает класс для хранения захваченных переменных (test, s1 и s2) и передает экземпляр делегата в лямбду, который превращается в метод анонимного класса. Другими словами, если вы выберете альтернативу, вы получите нечто очень похожее на то, что компилятор только что сгенерировал для вас.
В этом конкретном примере нет, в этом нет ничего плохого. Состояние, которое вы передали в другой поток, полностью содержится, и ни один из задействованных типов не имеет каких-либо проблем схожести потока.
Это хороший способ сделать это. Я не вижу недостатков в использовании лямбда-выражений. Все просто и чисто.
То, на что вы смотрите, называется закрытием. chuckj заявляет , что компилятор генерирует класс во время компиляции, который соответствует членам, доступ к которым осуществляется за пределами замыкания.
Единственное, о чем вам следует беспокоиться, это если у вас есть ref или out параметры. Хотя строки являются неизменяемыми, ссылки на них (или любые переменные) НЕ являются.
One potential problem with the pattern is that it's very tempting to expand it into something more-generic but less-safe like this (scratch code- don't expect it to work):
public static void QueueTwoParameterWorkItem<T1, T2>(T1 value1, T2 value2, workDelegate<T1,T2> work)
{
try
{
T1 param1 = value1;
T2 param2 = value2;
ThreadPool.QueueUserWorkItem(
(o) =>
{
work(param1, param2);
});
}
catch (Exception ex)
{
//exception logic
}
}