C# 如何使用委托/回调编写相同的代码?
这里有一个非常简单的例子,可以在互联网上找到异步/等待概念,我想知道如何使用开始/结束调用实现这个小逻辑? 我所需要做的就是使用这两种方法(异步/等待和委托)准备一个复杂的逻辑,所以我想从一个基本的工作流开始C# 如何使用委托/回调编写相同的代码?,c#,winforms,delegates,async-await,C#,Winforms,Delegates,Async Await,这里有一个非常简单的例子,可以在互联网上找到异步/等待概念,我想知道如何使用开始/结束调用实现这个小逻辑? 我所需要做的就是使用这两种方法(异步/等待和委托)准备一个复杂的逻辑,所以我想从一个基本的工作流开始 int countCharacters() { int count = 0; using (StreamReader reader= new StreamReader("D:\\Data.txt")) { s
int countCharacters()
{
int count = 0;
using (StreamReader reader= new StreamReader("D:\\Data.txt"))
{
string content = reader.ReadToEnd();
count = content.Length;
Thread.Sleep(5000);
}
return count;
}
private async void btnProcessFIle_Click(object sender, EventArgs e)
{
Task<int> task = new Task<int>(countCharacters);
task.Start();
int count = await task;
lblCount.Text = "No. of characters in file=" +Environment.NewLine+ count.ToString();
}
int countCharacters()
{
整数计数=0;
使用(StreamReader=newstreamreader(“D:\\Data.txt”))
{
字符串内容=reader.ReadToEnd();
计数=内容。长度;
睡眠(5000);
}
返回计数;
}
私有异步无效btnProcessFIle\u单击(对象发送方,事件参数e)
{
任务任务=新任务(countCharacters);
task.Start();
int count=等待任务;
lblCount.Text=“文件中的字符数=“+Environment.NewLine+count.ToString();
}
功能BeginInvoke可以访问非UI线程中的UI元素,因此您需要像这样更改代码:
private async void btnProcessFIle_Click(object sender, EventArgs e)
{
var task = Task.Run(() => {
var count = countCharacters();
lblCount.BeginInvoke((Action) (() =>
{
lblCount.Text = "No. of characters in file=" +Environment.NewLine+
count.ToString();
}));
});
await task;
}
没有异步/等待的代码。您不需要使用BeginInvoke,因为您可以使用
TaskScheduler.fromSynchronizationCurrentContext()
int countCharacters()
{
整数计数=0;
使用(StreamReader=newstreamreader(“D:\\Data.txt”))
{
字符串内容=reader.ReadToEnd();
计数=内容。长度;
睡眠(5000);
}
返回计数;
}
私有void btnProcessFIle\u单击(对象发送方,事件参数e)
{
任务任务=新任务(countCharacters);
task.Start();
var uiScheduler=TaskScheduler.FromCurrentSynchronizationContext();
task.ContinueWith(计数=>{
lblCount.Text=“文件中的字符数=“+Environment.NewLine+count.ToString();
},调度程序);
}
如果你真的想用BeginInvoke,我想你可以写
private void btnProcessFIle_Click(object sender, EventArgs e)
{
Task<int> task = new Task<int>(countCharacters);
task.Start();
var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
task.ContinueWith(count =>{
lblCount.BeginInvoke(()=>{
lblCount.Text = "No. of characters in file=" +Environment.NewLine+ count.ToString();
});
});
}
private void btnProcessFIle\u单击(对象发送方,事件参数e)
{
任务任务=新任务(countCharacters);
task.Start();
var uiScheduler=TaskScheduler.FromCurrentSynchronizationContext();
task.ContinueWith(计数=>{
lblCount.BeginInvoke(()=>{
lblCount.Text=“文件中的字符数=“+Environment.NewLine+count.ToString();
});
});
}
这是一个非常简单的例子,可以在互联网上找到异步/等待的概念
这是一个非常糟糕的例子
它使用任务构造函数和Start
,这是一个明确的禁忌(实际上没有有效的用例可以做到这一点)
在“异步示例”中,它还在后台线程上同步使用文件系统
如果您想要一个如何异步使用同步(例如,CPU绑定)代码的示例,那么这是一个更好的示例,它可以做几乎相同的事情:
int countCharacters()
{
Thread.Sleep(5000);
return 13;
}
private async void btnProcessFIle_Click(object sender, EventArgs e)
{
var count = await Task.Run(() => countCharacters());
lblCount.Text = "No. of characters in file=" + count;
}
请注意,这是一个如何从UI线程异步调用CPU绑定代码的示例—它不是“异步概念”的示例
我想知道如何使用Begin/End Invoke实现这个小逻辑
由于您的工作是在后台线程上进行同步工作,所以这实际上相当容易;不要创建自己的IAsyncResult
(这是APM真正困难的部分-如果确实需要实现它,请参阅中的“实现CLR异步编程模型”)
但是,由于您可以只使用Delegate.BeginInvoke
,因此非常简单:
private void btnProcessFIle_Click(object sender, EventArgs e)
{
var ui = SynchronizationContext.Current;
Func<int> d = countCharacters;
d.BeginInvoke(CountCharactersCallback, ui);
}
private void CountCharactersCallback(IAsyncResult ar)
{
var d = (Func<int>) ((AsyncResult) ar).AsyncDelegate;
var ui = (SynchronizationContext) ar.AsyncState;
try
{
var count = d.EndInvoke(ar);
ui.Post(CountCharactersComplete, count);
}
catch (Exception ex)
{
var edi = ExceptionDispatchInfo.Capture(ex);
ui.Post(CountCharactersError, state);
}
}
private void CountCharactersComplete(object state)
{
var count = (int) state;
lblCount.Text = "No. of characters in file=" + count;
}
private void CountCharactersError(object state)
{
var edi = (ExceptionDispatchInfo)state;
edi.Throw();
}
private void btnProcessFIle\u单击(对象发送方,事件参数e)
{
var ui=SynchronizationContext.Current;
Func d=可计数字符;
d、 BeginInvoke(CountCharactersCallback,ui);
}
私有void CountCharactersCallback(IAsyncResult ar)
{
var d=(Func)((AsyncResult)ar).AsyncDelegate;
var ui=(SynchronizationContext)ar.AsyncState;
尝试
{
var count=d.EndInvoke(ar);
ui.Post(CountCharactersComplete,count);
}
捕获(例外情况除外)
{
var edi=例外DispatchInfo.Capture(ex);
ui.Post(CountCharactersError,state);
}
}
私有void CountCharactersComplete(对象状态)
{
变量计数=(int)状态;
lblCount.Text=“文件中的字符数=”+计数;
}
私有void countCharacterError(对象状态)
{
var edi=(ExceptionDispatchInfo除外)状态;
edi.Throw();
}
注:
是一个“裸回调”。从CountCharactersCallback
传播的任何异常都表示发生灾难性错误CountCharacterScalBack
- 特别是,必须小心不要让
的异常传播到EndInvoke
回调之外。这是一个常见的错误BeginInvoke
- 我正在使用
同步回UI线程。这与等待的行为相同SynchronizationContext
- 我使用
跨线程保留异常堆栈跟踪(不需要包装异常)ExceptionDispatchInfo
只是直接在消息循环中引发异常。这与countCharacterError
的行为相同async void
private void btnProcessFIle_Click(object sender, EventArgs e)
{
var ui = SynchronizationContext.Current;
Func<int> d = countCharacters;
d.BeginInvoke(CountCharactersCallback, ui);
}
private void CountCharactersCallback(IAsyncResult ar)
{
var d = (Func<int>) ((AsyncResult) ar).AsyncDelegate;
var ui = (SynchronizationContext) ar.AsyncState;
try
{
var count = d.EndInvoke(ar);
ui.Post(CountCharactersComplete, count);
}
catch (Exception ex)
{
var edi = ExceptionDispatchInfo.Capture(ex);
ui.Post(CountCharactersError, state);
}
}
private void CountCharactersComplete(object state)
{
var count = (int) state;
lblCount.Text = "No. of characters in file=" + count;
}
private void CountCharactersError(object state)
{
var edi = (ExceptionDispatchInfo)state;
edi.Throw();
}