异步委托是c#项目从.net framework移植到.net core一个很让人头疼的问题。虽然.net framework会有其他一些方法无法兼容,但异步委托令人头疼的就是它不会在.net standard里报错,即使它并不能在.net core里生效。最近在处理项目兼容性的时候经常会遇到这个问题,在此做一下记录。
我们先来了解一下这个API的工作内容。 委托中的BeginInvoke相当于新开了一个线程去运行方法,让这个方法在后台运行。而EndInvoke就是返回该方法的返回值。
static void Main(string[] args)
{
Console.WriteLine("主线程的ID:" + Thread.CurrentThread.ManagedThreadId);//标记显示主线程ID
SayHello sayhello = new SayHello(Say);
IAsyncResult iResult=sayhello.BeginInvoke("Olive", null, null);//Delegate.BeginInvoke()方法实际上是一个IAsyncResult的对象
string result = sayhello.EndInvoke(iResult);//Delegate.EndInvoke()方法就是返回调用函数的返回值,但是该方法需要一个IAsyncResult对象,也就是委托调用BeginInvoke()开始异步
Console.WriteLine(result);
Console.ReadKey();
}
private static string Say(string name)
{
Console.WriteLine("Hello!--------" + name);
Console.WriteLine("当前的线程ID为:" + Thread.CurrentThread.ManagedThreadId);
return "I Love you " + name;
}
一般为了防止EndInvoke阻塞,会利用等待句柄。
if (iResult.AsyncWaitHandle.WaitOne(1000,false)) //如果等待超过1秒,则无法返回结果
{
string result = sayhello.EndInvoke(iResult);
Console.WriteLine(result);
}
因为这些委托的方法并不是在.net framework框架的库里声明的。 .NET编译时会将高级语言编译成一种称作IL的中间语言,编译时IL编译库中会给委托添加BeginInvoke和EndInvoke方法,而可移植性分析器只会报告在.net framework框架的库里声明的方法。
我们可以用Task来代替实现异步。 举个例子
delegate int WorkDelegate(int arg);
...
WorkDelegate del = DoWork;
// Calling del.BeginInvoke starts executing the delegate on a
// separate ThreadPool thread
Console.WriteLine("Starting with BeginInvoke");
var result = del.BeginInvoke(11, WorkCallback, null);
// This writes output to the console while DoWork is running in the background
Console.WriteLine("Waiting on work...");
// del.EndInvoke waits for the delegate to finish executing and
// gets its return value
var ret = del.EndInvoke(result);
可以用Task.Run来代替BeginInvoke,await来代替EndInvoke,达到异步运行的效果。
delegate int WorkDelegate(int arg);
...
WorkDelegate del = DoWork;
// Schedule the work using a Task and
// del.Invoke instead of del.BeginInvoke.
Console.WriteLine("Starting with Task.Run");
var workTask = Task.Run(() => del.Invoke(11));
// Optionally, we can specify a continuation delegate
// to execute when DoWork has finished.
var followUpTask = workTask.ContinueWith(TaskCallback);
// This writes output to the console while DoWork is running in the background.
Console.WriteLine("Waiting on work...");
// We await the task instead of calling EndInvoke.
// Either workTask or followUpTask can be awaited depending on which
// needs to be finished before proceeding. Both should eventually
// be awaited so that exceptions that may have been thrown can be handled.
var ret = await workTask;
await followUpTask;
本文章使用limfx的vscode插件快速发布