首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在一起使用任务和定时器

如何在一起使用任务和定时器
EN

Stack Overflow用户
提问于 2017-08-28 07:47:05
回答 1查看 579关注 0票数 0

下面的类用于将文本写入控制台,但是以一种更定时的方式,比如在电影(如 )中显示字符的方式,问题是我无法让类中的方法作为任务运行,特别是因为我使用的是计时器,而且我有多个相互链接的方法。

代码语言:javascript
运行
复制
    Private NotInheritable Class WriteText
    Private Shared i As Integer = 0
    Private Shared text As String = ""
    Private Shared audio As New Audio
    Private Shared audioFile As String = "C:\Users\jamisco\Documents\Sound for Jamisco\beep-29.wav"
    Shared call_command As Boolean
    Shared timer As New Timer

    Public Shared Sub Text2Write(ByVal Text2Type As String, Optional ByVal call_awaitcommand As Boolean = False)
        text = Text2Type
        call_command = call_awaitcommand
        Timer.Interval = typingInterval
        Timer.AutoReset = True
        Timer.Start()
        writing2console = True
        FinishedTyping = False
        i = 0
        AddHandler Timer.Elapsed, AddressOf Tick
        audio.Play(audioFile, AudioPlayMode.BackgroundLoop)
        While (writing2console)
            Console.ReadKey(True)
        End While

    End Sub

    Private Shared Sub Tick(ByVal sender As Object, ByVal e As ElapsedEventArgs)

        If (text.Length >= 0 And timer.Enabled) Then
            If i < text.Length Then
                Console.Write(text(i))
                i += 1
            Else
                Reset()
            End If
        End If

    End Sub

    Public Shared Sub StopTyping()
        Reset()
    End Sub

    Private Shared Sub Reset()
        Console.WriteLine()
        audio.Stop()
        'timer.Stop()
        timer.Stop()
        i = 0
        writing2console = False
        FinishedTyping = True
        If (call_command) Then
            _jamisco.AwaitCommand()
        End If
    End Sub
End Class
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-08-28 17:16:22

这就是你想要达到的效果吗?

代码语言:javascript
运行
复制
using System;
using System.Threading.Tasks;

namespace asyncConsoleTyping
{
    class Program
    {
        private static Random _rnd = new Random();

        public static void Main(string[] args)
        {
            AsyncMain().Wait();
        }

        public static async Task AsyncMain()
        {
            await Type("This is a test");
            await Type("This is another test");
            await Type("What is your name?");
            var name = Console.ReadLine();
            await Type($"Hello {name}!");

            Console.Read();  
        }

        public static async Task Type(string text)
        {
            var prevColor = Console.ForegroundColor;
            Console.ForegroundColor=ConsoleColor.Green;
            foreach (char c in text)
            {
                Console.Write(c);
                await Task.Delay(10 + _rnd.Next(30));
            }
            Console.WriteLine();
            Console.ForegroundColor = prevColor;
        }
    }
}

这是通过一次异步打印字符串来实现的,每个字符串之间都有一个小的随机延迟。它还会在打印时更改文本颜色,然后再进行还原。您可以使用await Type(SomeString)调用它,并且控制台在打印字符时不会锁定。在打印完整个await之后,将在下一行继续执行。它实际上并不使用Timer,因为有更合适的基于Task的机制来实现这一点(Task.Delay)。

为了让控制台应用程序正确地使用async await,您必须使用一个小“技巧”,因为Main不能是Task。只需创建一个AsyncMain函数,如我的示例所示,并使用AsyncMain().Wait()Main调用它。一旦C# 7.1发布,您就不需要这样做了,就像public static Task Main(string[] args); (以及其他) 将被视为有效的入境点。一样。

对于异步控制台应用程序,您还可以阅读一些关于这里的其他“陷阱”。

您可以通过使用async Task及其创建的CancellationToken取消对CancellationTokenSource的调用。

任何可以取消的Task都应该接受CancellationToken作为参数。该令牌是通过调用Token函数在CancellationTokenSource上创建的。创建源时,可以指定超时值(var cts = new CancellationTokenSource(1000);),也可以从具有令牌引用的任何地方调用Cancel (cts.Cancel)。然后,您的async方法可以将该令牌传递给它等待的任何东西(支持取消)。它还应该定期检查IsCancellationRequested,看看是否应该取消它的工作。

这是支持取消的上述示例的一个版本:

代码语言:javascript
运行
复制
using System;
using System.Threading;
using System.Threading.Tasks;

namespace asyncConsoleTyping
{
    class Program
    {
        private static Random _rnd = new Random();

        public static void Main(string[] args)
        {
            AsyncMain().Wait();
        }

        public static async Task AsyncMain()
        {
            await Type("This is a test");
            await Type("This is another test");
            await Type("What is your name?");
            var name = Console.ReadLine();
            await Type($"Hello {name}!");

            var cts = new CancellationTokenSource(1000); //Auto-cancels after 1 second
            try
            {
                await Type("This String can get canceled via a CancellationToken", cts.Token);
            }
            catch (Exception ex)
            {
                Console.ForegroundColor=ConsoleColor.Red;
                Console.WriteLine($"Canceled: {ex.Message}");
            }
        }

        public static Task Type(string text)
        {
            return Type(text, CancellationToken.None); //This overload doesn't support cancellation, but it calls the one that does.  Passing in CancellationToken.None allows it to work without checking to see if a "real" token was passed.
        }

        public static async Task Type(string text, CancellationToken ct)
        {
            var prevColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Green;
            foreach (char c in text)
            {
                Console.Write(c);
                await Task.Delay(10 + _rnd.Next(30), ct); //Pass the Cancellationtoken in to Task.Delay so the delay can be canceled
                if (ct.IsCancellationRequested) //Check to see if the task was canceled, if so, exit the loop through the characters.
                {
                    break;
                }
            }
            Console.WriteLine();
            Console.ForegroundColor = prevColor;
        }
    }
}

上面的例子显示了取消实际上有一个微妙的错误,它可能导致控制台的颜色不被重置。await Task.Delay(10 + _rnd.Next(30), ct);将在“取消”上抛出异常,而不进入颜色重置代码。可以通过将其更改为:

代码语言:javascript
运行
复制
public static async Task Type(string text, CancellationToken ct)
{
    var prevColor = Console.ForegroundColor;
    Console.ForegroundColor = ConsoleColor.Green;
    try
    {
        foreach (char c in text)
        {
            Console.Write(c);
            await Task.Delay(10 + _rnd.Next(30), ct);
        }
    }
    finally
    {
        Console.WriteLine();
        Console.ForegroundColor = prevColor;
    }
    ct.ThrowIfCancellationRequested(); //Omit this line if you don't want an exception thrown on cancellation (but be aware of the consequences!)
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45914120

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档