Анонимные методы и делегаты
Я пытаюсь понять, почему метод BeginInvoke не принимает анонимный метод.
void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (InvokeRequired)
{
//Won't compile
BeginInvoke(delegate(object sender, ProgressChangedEventArgs e)
{ bgWorker_ProgressChanged(sender, e); });
}
progressBar1.Increment(e.ProgressPercentage);
}
Он говорит мне: "Невозможно преобразовать из" анонимного метода "в" System.Delegate ", а когда я передаю анонимный метод делегату, он работает?
BeginInvoke((progressDelegate)delegate { bgWorker_ProgressChanged(sender, e); });
Ответы
Ответ 1
Класс Delegate является базовым классом для типов делегатов. Однако только система и компиляторы могут быть получены явно из класса Delegate или из класса MulticastDelegate. Также недопустимо выводить новый тип из типа делегата. Класс Delegate не считается типом делегата; это класс, используемый для получения типов делегатов.
Источник - MSDN
Следовательно, необходимо, чтобы явный приведение к типу производного от делегата. Вы столкнулись с этой конкретной ошибкой компилятора, когда вы передаете анонимный метод для параметра типа System.Delegate - к счастью, это редкий сценарий. Это слишком большая гибкость.
delegate void MyDelegate();
static void DoSomething_Flexible(Delegate d)
{ d.DynamicInvoke(); }
static void DoSomething_Usable(MyDelegate d)
{ d(); }
static void Main(string[] args)
{
// requires explicit cast else compile error Error "Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type
DoSomething_Flexible((MyDelegate) delegate { Console.WriteLine("Flexible is here!"); });
// Parameter Type is a .NET Delegate, no explicit cast needed here.
DoSomething_Usable(delegate { Console.WriteLine("Usable is here!"); });
}
Подробнее об этом на этой странице Ян Гриффит. (См. Парас после заголовка Notes)
Ответ 2
Вам нужно сообщить компилятору, какой тип делегата создать, так как Invoke
(и т.д.) просто возьмите Delegate
(а не что-то более конкретное).
Чтобы применить к самой большой аудитории, MethodInvoker
- удобный тип делегата
BeginInvoke((MethodInvoker) delegate(...) {...});
Однако... BackgroundWorker.ProgressChanged
автоматически запускается в потоке пользовательского интерфейса, поэтому вам это даже не нужно.
Ответ 3
В большинстве случаев вы имеете дело с делегатом без параметров или с предикатом в этих случаях. Самый простой способ его сортировки заключается в том, чтобы направить ваш анонимный метод непосредственно на Action
или Predicate
соответственно; вам просто не нужно создавать пользовательский тип делегата для таких простых вещей.
Итак, у вас будет что-то вроде
BeginInvoke((Action)delegate(){YourCode.DoSomething();});
или
BeginInvoke((Predicate)delegate(object yourParameter){return YourCode.IsTheParameterSomething(yourParameter)});
НТН