C# 委托向回调函数返回了值
虽然我认为解决以下问题并不困难,但我遇到了一个非常棘手的问题: 我有一个应用程序,当你点击一个按钮时,它会调用一个委托。看起来是这样的:C# 委托向回调函数返回了值,c#,asp.net,multithreading,winforms,C#,Asp.net,Multithreading,Winforms,虽然我认为解决以下问题并不困难,但我遇到了一个非常棘手的问题: 我有一个应用程序,当你点击一个按钮时,它会调用一个委托。看起来是这样的: private void button1_Click(object sender, EventArgs e) { MyTaskWorkerDelegate worker = new MyTaskWorkerDelegate(returnANumber); AsyncCallback completedCallba
private void button1_Click(object sender, EventArgs e)
{
MyTaskWorkerDelegate worker = new MyTaskWorkerDelegate(returnANumber);
AsyncCallback completedCallback = new AsyncCallback(DelegateMethod);
object[] myArray = new object[1];
myArray[0] = "The number is: ";
worker.BeginInvoke(completedCallback,myArray);
}
private int returnANumber()
{
Thread.Sleep(1000);
return 100;
}
private void DelegateMethod(IAsyncResult arr)
{
object[] myArray = (object[])arr.AsyncState;
//Messagebox should show "The number is: 100"
MessageBox.Show(myArray[0].ToString() + theNumberFromTheMethos);
}
方法“returnANumber”应该休眠一秒钟,然后返回数字100。
看起来是这样的:
private void button1_Click(object sender, EventArgs e)
{
MyTaskWorkerDelegate worker = new MyTaskWorkerDelegate(returnANumber);
AsyncCallback completedCallback = new AsyncCallback(DelegateMethod);
object[] myArray = new object[1];
myArray[0] = "The number is: ";
worker.BeginInvoke(completedCallback,myArray);
}
private int returnANumber()
{
Thread.Sleep(1000);
return 100;
}
private void DelegateMethod(IAsyncResult arr)
{
object[] myArray = (object[])arr.AsyncState;
//Messagebox should show "The number is: 100"
MessageBox.Show(myArray[0].ToString() + theNumberFromTheMethos);
}
当睡眠结束并返回号码时,棘手的部分就来了。在click函数中创建的数组被传递给回调方法。这个方法应该显示一个MessageBox,其中显示数组的字符串和从委托返回的数字。函数如下所示:
private void button1_Click(object sender, EventArgs e)
{
MyTaskWorkerDelegate worker = new MyTaskWorkerDelegate(returnANumber);
AsyncCallback completedCallback = new AsyncCallback(DelegateMethod);
object[] myArray = new object[1];
myArray[0] = "The number is: ";
worker.BeginInvoke(completedCallback,myArray);
}
private int returnANumber()
{
Thread.Sleep(1000);
return 100;
}
private void DelegateMethod(IAsyncResult arr)
{
object[] myArray = (object[])arr.AsyncState;
//Messagebox should show "The number is: 100"
MessageBox.Show(myArray[0].ToString() + theNumberFromTheMethos);
}
我不知道如何访问委托方法返回的值。。。
请帮助我:(您可以通过
MyTaskWorkerDelegate.EndInvoke
访问返回值。因此,您必须保留对MyTaskWorkerDelegate
的引用,并将其传递到DelegateMethod
。按照代码当前的外观,您需要一个单独的对象来通过myArray
和MyTaskWorkerDelegate
传递IAsyncResult.AsyncState
如果使用匿名lambda/delegate并访问局部变量,则可以避免这种情况并大大简化代码。C#编译器将发挥保持状态的神奇作用:
private void button1_Click(object sender, EventArgs e)
{
MyTaskWorkerDelegate worker = new MyTaskWorkerDelegate(returnANumber);
object[] myArray = new object[1];
myArray[0] = "The number is: ";
AsyncCallback completedCallback = new AsyncCallback((ar) =>
{
var result = worker.EndInvoke(ar);
// you cannot use MessageBox here, you're on a non-UI random pool thread
Debug.Print(myArray[0].ToString() + result);
});
worker.BeginInvoke(completedCallback, null); // no need to pass the state
}
还有一点,您不能从AsyncCallback
委托中使用MessageBox
,调用回调时您处于随机池线程中。您需要使用:
AsyncCallback completedCallback = new AsyncCallback((ar) =>
{
var result = worker.EndInvoke(ar);
// you cannot use MessageBox here, you're on a non-UI random pool thread
this.BeginInvoke(new MethodInvoker(() =>
{
// here you can use MessageBox, you're on the UI thread
MessageBox.Show(myArray[0].ToString() + result);
}));
});
注意,Control.BeginInvoke
的用途与Delegate.BeginInvoke
完全不同,尽管名称相似。它用于在WinForms UI线程上异步调用回调
也就是说,如果您可以使用.NET 4.5(或.NET 4.0+和VS2012+),您可以使用@SLaks指出的和async/await
来简化代码事件。您的代码可能很简单:
private int returnANumber()
{
Thread.Sleep(1000);
return 100;
}
private async void button1_Click(object sender, EventArgs e)
{
object[] myArray = new object[1];
myArray[0] = "The number is: ";
int result = await Task.Run(() => returnANumber());
MessageBox.Show(myArray[0].ToString() + result);
}
此外,如果Thread.Sleep(1000)
的唯一原因是暂停,则可以使用Task.Delay
:
private async Task<int> returnANumber()
{
await Task.Delay(1000);
return 100;
}
private async void button1_Click(object sender, EventArgs e)
{
object[] myArray = new object[1];
myArray[0] = "The number is: ";
int result = await returnANumber();
MessageBox.Show(myArray[0].ToString() + result);
}
private async Task returnANumber()
{
等待任务。延迟(1000);
返回100;
}
私有异步无效按钮1\u单击(对象发送方,事件参数e)
{
object[]myArray=新对象[1];
myArray[0]=“数字为:”;
int result=wait returnANumber();
显示(myArray[0].ToString()+结果);
}
这样,您就不会显式地使用池线程。您应该用
Task.Run()
替换所有这些,这更易于使用。我编辑了您的标记并删除了[asp.net]。我假设这是一个WinForms应用程序,就像您使用MessageBox的方式一样。显示和按钮1\u单击。非常感谢您的回答,太棒了!我使用TPL解决方案,因为应用程序已经内置在.NET 4.5中。这非常简单!再次感谢!@Coloso,没问题,很高兴它有所帮助。如果您继续使用TPL/a同步/等待,请确保检查此处的链接: