如何停止System.Threading.Timer

时间:2016-10-10 21:17:08

标签: c# multithreading timer

所以我有一个系统,你可以设置叫出租车(这是一个游戏应用程序),这辆出租车需要10秒钟。问题是 我也有一个canceltaxi功能,我需要知道如何停止System.Threading.Timer,因为当他们订购出租车时,取消它 让他们说8秒然后直接他们订购另一辆出租车后,那辆出租车需要2秒才能到达而不是10所以它仍然使用旧的出租车计时器, 我怎么阻止它?

我已经尝试过这段代码,但它仍然没有停止..当我想取消它时,我称之为无效。

public void StopTaxiTimer()
        {
            taxiTimerInstance.Dispose();
            taxiTimerInstance = null;
            this.Dispose();
        }

全班:

using log4net;
using Plus.Communication.Packets.Outgoing.Rooms.Chat;
using Plus.HabboHotel.GameClients;
using Plus.HabboHotel.Roleplay.Instance;
using Plus.HabboHotel.Rooms;
using System;
using System.Threading;

namespace Plus.HabboHotel.Roleplay.Timers
{
    public sealed class TaxiTimer : IDisposable
    {
        private static readonly ILog myLogger = LogManager.GetLogger("Plus.HabboHotel.Roleplay.Timers.DeathTimer");

        private Timer taxiTimerInstance;
        private uint timerTimeSeconds;
        private RoleplayInstance roleplayInstance;

        public TaxiTimer(RoleplayInstance roleplayInstance)
        {
            Console.WriteLine("Setup TaxiTimer for " + roleplayInstance.GetSession().GetHabbo().Username + " (" + roleplayInstance.TaxiWaitTimeSeconds + " seconds)");
            this.timerTimeSeconds = roleplayInstance.TaxiWaitTimeSeconds;
            this.roleplayInstance = roleplayInstance;
            this.taxiTimerInstance = new Timer(new TimerCallback(this.OnTimerElapsed), null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
        }

        public void OnTimerElapsed(object Obj)
        {
            try
            {
                if (taxiTimerInstance == null)
                    return;

                if (roleplayInstance == null || !roleplayInstance.CalledTaxi || roleplayInstance.GetSession() == null || roleplayInstance.GetSession().GetHabbo() == null)
                    return;

                GameClient gameSession = roleplayInstance.GetSession();

                if (roleplayInstance.TaxiWaitTimeSeconds < 1)
                {
                    Room currentRoom = gameSession.GetHabbo().CurrentRoom;
                    if (currentRoom == null)
                        return;

                    RoomUser roomUser = currentRoom.GetRoomUserManager().GetRoomUserByHabbo(gameSession.GetHabbo().Id);
                    if (roomUser == null)
                        return;

                    roleplayInstance.CalledTaxi = false;
                    currentRoom.SendMessage(new ShoutComposer(roomUser.VirtualId, "*Gets transported to my destination*", 0, roomUser.LastBubble));
                    gameSession.GetHabbo().PrepareRoom(roleplayInstance.TaxiRoomId, string.Empty);
                }
                else
                {
                    roleplayInstance.TaxiWaitTimeSeconds--;
                }
            }
            catch (Exception ex)
            {
                myLogger.Error(ex.Message);
                myLogger.Error(ex.StackTrace);
            }
        }

        public void StopTaxiTimer()
        {
            taxiTimerInstance.Dispose();
            taxiTimerInstance = null;
            this.Dispose();
        }

        public void Dispose()
        {
            GC.SuppressFinalize(this);
        }
    }
}

在CallTaxi上:

roleplayInstance.TaxiWaitTimeSeconds = Convert.ToUInt32(PlusEnvironment.GetRPManager().GetSettings().GetSettingValueByKey("roleplay_taxi_wait_seconds"));
                    roleplayInstance.TaxiRoomId = goingTo.RoomId;
                    roleplayInstance.TaxiTimer = new HabboHotel.Roleplay.Timers.TaxiTimer(roleplayInstance);

4 个答案:

答案 0 :(得分:4)

  

我需要知道如何停止System.Threading.Timer,因为当他们订购出租车时,在他们说8秒之后取消它然后在他们订购另一辆出租车之后直接取消,出租车需要2秒才能到达而不是10仍然使用旧的出租车计时器,我该如何阻止它?

退后一步。如果你从来没有制作计时器,你不必担心取消计时器。

您正在描述带有取消的异步工作流程。 C#和.NET框架已经有了这个功能,所以请使用它而不是尝试自己动手。

制作一个async工作流方法await Task.Delay任务需要CancellationToken。延误的延续是出租车的到来;取消方法通过取消令牌导致任务失败。

这个机制有很多文档,所以开始阅读它。一个好的起点是:

https://msdn.microsoft.com/en-us/library/dd997364

答案 1 :(得分:1)

您的代码似乎有很多瑕疵。我看到了一些警告信号。

您没有正确实施IDisposable。应该更像这样:

public class ExampleDisposable : IDisposable 
{
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing) 
        {
            // free managed resources
        }
        // free native resources if there are any.
    }
}

您还使用了事件处理程序的事件引发方法命名约定。引发事件的方法通常称为On*,处理这些事件的方法为*。因此,在您的情况下,按惯例而不是public void OnTimerElapsed(object Obj)它应该是public void TimerElapsed(object Obj)

此外,您正在使用catch (Exception ex)捕获异常。这只是一个糟糕的反模式。阅读Eric Lippert's Vexing Exceptions

现在,最后,我建议你无论如何都要避免这种类。请改用Microsoft的Reactive框架(NuGet“System.Reactive”)。

然后你可以这样写:

Subject<RoleplayInstance> requestTaxi = new Subject<RoleplayInstance>();

IDisposable subscription =
    requestTaxi
        .Select(ri =>
            ri == null
            ? Observable.Never<RoleplayInstance>()
            : Observable
                .Timer(TimeSpan.FromSeconds((double)ri.TaxiWaitTimeSeconds))
                .Select(n => ri))
        .Switch()
        .Subscribe(ri =>
        {
            GameClient gameSession = ri.GetSession();
            Room currentRoom = gameSession.GetHabbo().CurrentRoom;
            RoomUser roomUser = currentRoom.GetRoomUserManager().GetRoomUserByHabbo(gameSession.GetHabbo().Id);
            currentRoom.SendMessage(new ShoutComposer(roomUser.VirtualId, "*Gets transported to my destination*", 0, roomUser.LastBubble));
            gameSession.GetHabbo().PrepareRoom(roleplayInstance.TaxiRoomId, string.Empty);
        });

现在,当你想打电话叫出租车时,你只需要写requestTaxi.OnNext(roleplayInstance);。如果您在出租车被叫之前第二次呼叫,则事件会自动重启。如果您使用requestTaxi.OnNext(null);调用它,则它会取消当前的任何请求,但仍然可以在以后处理新的请求。

如果您完全关闭,请拨打subscription.Dispose();。我认为所有这些都更整洁。

答案 2 :(得分:1)

您是否阅读过Timer.Change方法的工具提示?试试这个:

timer.Change(Timeout.Infinite, Timeout.Infinite);

答案 3 :(得分:1)

_timer.Change(Timeout.Infinite, Timeout.Infinite);
_timer = null;