我怎样才能获得任务1所述的同等学历; T>在.NET 3.5中?同等学历、所述、任务、NET

2023-09-07 03:36:12 作者:青春有个放肆的梦

我有一个使用任务与其中一些code; T> 会推迟从串行读操作返回结果的时间很短,像这样的:

 无效ReturnResponseAfterAShortDelay()
{
    如果(delayedResponseCancellationTokenSource!= NULL)
        delayedResponseCancellationTokenSource.Cancel(); //取消未完成操作,并开始一个新的。

   delayedResponseCancellationTokenSource =新CancellationTokenSource();

   log.InfoFormat(推迟响应{0}毫秒,Settings.Default.TimeoutMs);

   Task.Delay(Properties.Settings.Default.TimeoutMs,delayedResponseCancellationTokenSource.Token)
       .ContinueWith((续)=> ReturnWhateverHasArrived(),TaskContinuationOptions.NotOnCanceled)
       。开始();
}
 

这背后code这个想法是在没有新的人物到达指定的时间间隔,返回的结果。

不过,由于我无法控制的因素,我必须使用.NET 3.5,其中$ P $使用pvents我任务< T> ,所以我必须重构这code莫名其妙。

我怎样才能达到同样的效果,而无需使用任务< T>

澄清

虽然具体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(_ => NEXTSTEP()))
                {
                    timer.Change(0,500);

                    VAR刻度= 0;
                    而(打勾小于10)
                    {
                        在一个时钟嘀哒//恢复
                        得到的回报Type.Missing;
                        Console.WriteLine(嘀+打勾++);
                    }
                }

                this.Completed(这一点,EventArgs.Empty);
            }

            公共无效启动()
            {
                IEnumerator的枚举= NULL;
                行动NEXTSTEP =()=> enumerator.MoveNext();
                枚举= WorkAsync(NEXTSTEP).GetEnumerator();
                下一步();
            }
        }

        静态无效的主要(字串[] args)
        {
            VAR MRE =新的ManualResetEvent(假);
            VAR asyncLogic =新AsyncLogic();
            asyncLogic.Completed + =(S,E)=> mre.Set();
            asyncLogic.Start();
            mre.WaitOne();
            Console.WriteLine(已完成,preSS Enter退出);
            到Console.ReadLine();
        }
    }
}
 

任何事件可以被包裹着处理这将称之为 NEXTSTEP ,类似上面的计时器回调。在code将继续对应收益率回归后的,在事件。

有相当多的实现采用这种方法的优势,例如,杰弗里里希特的AsyncEnumerator 。

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.