【问题标题】:Call a method (with an argument) after a delay延迟后调用方法(带参数)
【发布时间】:2013-11-21 04:30:48
【问题描述】:

我想将一个变量传递给一个延迟后运行的函数。我已经看到有关如何执行此操作的类似问题(见下文)。我不认为这是我想要的,因为每次调用 method1 时,附加的匿名函数的数量都会增加?我需要做的是在添加新的匿名函数之前删除任何现有的附加匿名函数。但我不认为这是可能的。有没有办法在延迟后调用方法但每次都传入一个变量的新值?

using System.Timers;

myTimer = new Timer();
myTimer.Interval = 3000;
myTimer.AutoReset = false;

public void method1(int var1){
    myTimer.Elapsed += delegate { doSomething(var1); };
    myTimer.Start();
}

public void doSomething(int arg1){...}

更新

基本上每当运行method1 时,我希望在 3 秒后发生一些事情,并且我需要传入一个每次都可能不同的参数。

我认为我不能使用字段来存储变量,因为method1 在第一个计时器到期之前可能会被调用多次。 IE。可能有几个排队。例如。在某个时间点,等待发生的“doSomething”问题可能是......

doSomething(3)
doSomething(7)
doSomething(1)

它只是在测试台中使用,method1 将被运行调用不超过 50 次。我要确保的是每个 doSomething(var1) 只被调用一次,而不是每 3 秒调用一次。即每次调用method1 时只调用一个doSomething

这是一个 Windows 控制台应用程序。

【问题讨论】:

  • 你为什么不把你的参数移动到一个字段中,并将其用作共享资源?
  • @Redwan,不能那样做,我已经更新了我的问题。
  • 变量中有哪些数据?您是否希望每次针对不同的数据执行相同的逻辑,或者甚至可能执行不同的逻辑?
  • 您实际上并没有说明您希望它如何工作。那么当有人调用该方法,然后在 1 秒内再次调用它,会发生什么?是否应该仅在var1 的第二个值上调用doSomething?如果是这样,它应该在什么时候调用它,在 2 秒内,还是在 3 秒内?
  • @spiderplant0 字段有什么问题?我无法理解。您希望在调用 doSomething 或使用 methodRunRegularly 调用的所有值时将最后一个值作为参数传递?

标签: c#


【解决方案1】:

使用 TPL (& .Net 4.5),您可以执行以下操作:

public static class ActionExtensions
{
    public static async void DelayFor(this Action act, TimeSpan delay)
    {
        await Task.Delay(delay);
        act();
    }
}

//usage
Action toDo = () => doSomething(var1);
toDo.DelayFor(TimeSpan.FromSeconds(3));

...或者这对您的应用程序可能更简单:

static async void DoSomethingLater(int n)
{
    await Task.Delay(TimeSpan.FromSeconds(3));
    //DoSomething(n);
}

//usage
void Method1(int n)
{
    DoSomethingLater(n);
}

【讨论】:

  • 哦,是的!我还没有“接受”Task.Delay... 不错。异步 void 呢? :o!静止 + 1
  • 是的,我没有足够的上下文,但感觉Method1 是一个事件处理程序,async void 应该没问题。
【解决方案2】:

使用System.Timers.Timer 没有好方法。

使用System.Threading.Timer,您可以将userState 对象传递给构造函数。然后,该对象在每个滴答声中传递给计时器回调。例如:

string Whatever = "foo";
System.Threading.Timer timer = 
    new System.Threading.Timer(MyTimerCallback, whatever, 100, 100);

void MyTimerCallback (object state)
{
    string theData = (string)state;
    // at this point, theData is a reference to the "Whatever" string.
    // do tick processing
}

如果需要,您可以扩展 System.Timers.Timer,并添加一个属性来保存您的数据。比如:

class DerivedTimer : System.Timers.Timer
{
    public string Foo { get; set; }
}

myTimer = new DerivedTimer();
myTimer.Interval = 3000;

public void methodRunRegularly(int var1){
    myTimer.Foo = "Foobar!";
    myTimer.Elapsed += doSomething;
    myTimer.Start();
}

public void doSomething(object sender, EventArgs e)
{
    var t = (DerivedTimer)sender;
    var foo = t.Foo;
    // do processing
}

sender 参数中传递对计时器的引用。您可以直接转换它,然后引用您在初始化计时器时设置的Foo 属性。

【讨论】:

    【解决方案3】:

    这利用了响应式扩展(使用 nuget 包“rx-main”)。

    运行一个延迟 3 秒的方法:

    public void method1(int value)
    {
        ThreadPoolScheduler.Instance.Schedule(
            TimeSpan.FromSeconds(3), () => doSomething(value));
    }
    

    差不多就是这么短!

    【讨论】:

      猜你喜欢
      • 2014-05-06
      • 1970-01-01
      • 2013-11-06
      • 2012-07-22
      • 2011-03-05
      • 1970-01-01
      • 2019-03-15
      • 1970-01-01
      相关资源
      最近更新 更多