我怎样才能获得任务1所述的同等学历; T&GT;在.NET 3.5中? [英] How can I get the equivalent of Task<T> in .net 3.5?
问题描述
我有一个使用任务与其中一些code; T&GT;
会推迟从串行读操作返回结果的时间很短,像这样的:
无效ReturnResponseAfterAShortDelay()
{
如果(delayedResponseCancellationTokenSource!= NULL)
delayedResponseCancellationTokenSource.Cancel(); //取消未完成操作,并开始一个新的。
delayedResponseCancellationTokenSource =新CancellationTokenSource();
log.InfoFormat(推迟响应{0}毫秒,Settings.Default.TimeoutMs);
Task.Delay(Properties.Settings.Default.TimeoutMs,delayedResponseCancellationTokenSource.Token)
.ContinueWith((续)=&GT; ReturnWhateverHasArrived(),TaskContinuationOptions.NotOnCanceled)
。开始();
}
这背后code这个想法是在没有新的人物到达指定的时间间隔,返回的结果。
不过,由于我无法控制的因素,我必须使用.NET 3.5,其中$ P $使用pvents我任务&LT; T&GT;
,所以我必须重构这code莫名其妙。
我怎样才能达到同样的效果,而无需使用任务&LT; T&GT;
澄清
虽然具体code我发现正好是一个时间延迟,我的使用不仅限于拖延的事情。可能有其他情况下,我想立即启动一些长期运行轮询任务。一个典型的情况是一个I / O限制的操作,例如东西定期查询连接到串行端口的设备,然后提出了在满足一定条件的事件。
虽然具体code我发现正好是一个时间延迟,我 用途并不限定于延迟的东西。还可能有其他情况下 我想立即启动一些长期运行轮询任务。一个 典型的情况是I / O限制的操作,例如 东西定期查询连接到串行设备 端口,然后提出了在满足一定条件的事件。
有一个显着的和方便的破解编码这种情况下用C#2.0 - 4.0是使用自驱动的IEnumerable
和收益率
。它可以实现异步状态机,类似于的C#5.0异步/计谋
。这样,你让你的异步逻辑的便利线性code流动。所有的C#语言code控制语句的工作(除了你不能做收益率回报
从内的try / catch
)。
例如,一个带计时器的控制台应用程序:
使用系统;
System.Collections中使用;
使用的System.Threading;
命名空间ConsoleApplication_22516303
{
类节目
{
类AsyncLogic
{
公共事件处理程序已完成委托= {};
IEnumerable的WorkAsync(动作NEXTSTEP)
{
使用(VAR定时器=新System.Threading.Timer(_ =&GT; NEXTSTEP()))
{
timer.Change(0,500);
VAR刻度= 0;
而(打勾小于10)
{
在一个时钟嘀哒//恢复
得到的回报Type.Missing;
Console.WriteLine(嘀+打勾++);
}
}
this.Completed(这一点,EventArgs.Empty);
}
公共无效启动()
{
IEnumerator的枚举= NULL;
行动NEXTSTEP =()=&GT; enumerator.MoveNext();
枚举= WorkAsync(NEXTSTEP).GetEnumerator();
下一步();
}
}
静态无效的主要(字串[] args)
{
VAR MRE =新的ManualResetEvent(假);
VAR asyncLogic =新AsyncLogic();
asyncLogic.Completed + =(S,E)=&GT; mre.Set();
asyncLogic.Start();
mre.WaitOne();
Console.WriteLine(已完成,preSS Enter退出);
到Console.ReadLine();
}
}
}
任何事件可以被包裹着处理这将称之为 NEXTSTEP
,类似上面的计时器回调。在code将继续对应收益率回归后的
,在事件。
有相当多的实现采用这种方法的优势,例如,杰弗里里希特的AsyncEnumerator <$ C C $>。
I have some code that is using Task<T>
which defers returning a result from a serial read operation for a short time, like this:
void ReturnResponseAfterAShortDelay()
{
if (delayedResponseCancellationTokenSource != null)
delayedResponseCancellationTokenSource.Cancel(); // Cancel any pending operations and start a new one.
delayedResponseCancellationTokenSource = new CancellationTokenSource();
log.InfoFormat("Deferring response for {0} ms", Settings.Default.TimeoutMs);
Task.Delay(Properties.Settings.Default.TimeoutMs, delayedResponseCancellationTokenSource.Token)
.ContinueWith((continuation) => ReturnWhateverHasArrived(), TaskContinuationOptions.NotOnCanceled)
.Start();
}
The idea behind this code is to return the result when no new characters have arrived for a specified interval.
However, due to factors outside of my control, I must use .NET 3.5, which prevents me using Task<T>
, so I have to refactor this code somehow.
How can I achieve the same result, without using Task<T>
?
Clarification
Although the specific code I showed happens to be a timed delay, my usage isn't limited to delaying things. There may be other cases where I want to start some 'long running' polling task immediately. A typical situation would be an I/O bound operation, for example something the periodically queries a device attached to the serial port and then raises an event when some condition is met.
Although the specific code I showed happens to be a timed delay, my usage isn't limited to delaying things. There may be other cases where I want to start some 'long running' polling task immediately. A typical situation would be an I/O bound operation, for example something the periodically queries a device attached to the serial port and then raises an event when some condition is met.
A notable and handy hack for coding such scenarios with C# 2.0 - 4.0 is to use self-driven IEnumerable
and yield
. It allows to implement an asynchronous state machine, similar to async/await
of C# 5.0. This way you keep the convenient linear code flow for your asynchronous logic. All C# language code control statements work (besides you can't do yield return
from inside try/catch
).
For example, a console app with a timer:
using System;
using System.Collections;
using System.Threading;
namespace ConsoleApplication_22516303
{
class Program
{
class AsyncLogic
{
public EventHandler Completed = delegate { };
IEnumerable WorkAsync(Action nextStep)
{
using (var timer = new System.Threading.Timer(_ => nextStep()))
{
timer.Change(0, 500);
var tick = 0;
while (tick < 10)
{
// resume upon next timer tick
yield return Type.Missing;
Console.WriteLine("Tick: " + tick++);
}
}
this.Completed(this, EventArgs.Empty);
}
public void Start()
{
IEnumerator enumerator = null;
Action nextStep = () => enumerator.MoveNext();
enumerator = WorkAsync(nextStep).GetEnumerator();
nextStep();
}
}
static void Main(string[] args)
{
var mre = new ManualResetEvent(false);
var asyncLogic = new AsyncLogic();
asyncLogic.Completed += (s, e) => mre.Set();
asyncLogic.Start();
mre.WaitOne();
Console.WriteLine("Completed, press Enter to exit");
Console.ReadLine();
}
}
}
Any event could be wrapped with a handler which would call nextStep
, similar to the above timer callback. The code would continue after the corresponding yield return
, upon the event.
There are quite a few implementations taking advantage of this approach, e.g., Jeffrey Richter's AsyncEnumerator
.
这篇关于我怎样才能获得任务1所述的同等学历; T&GT;在.NET 3.5中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!