Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to pass multiple parameters to a Threading.Timer callback method?

On the past few projects of mine I've run into situations where I need to pass multiple parameters to a Threading.Timer callback method. Unfortunately, the constructor only accepts a single object parameter. Not wanting to use global variables, the pattern I've started using to overcome this problem is to pass in an anonymous method when the timer is created and use the compiler's ability to capture variables to my advantage, like so:

public void SendEmailsRepeatedly(IEnumerable<SimpleEmail> emails, int sendRepeatedlyDelayMS)
{
    Tokenizer tokenizer = new StandardTokenizer();

    sendRepeatedlyTimer = new Timer(
        SendRepeatedlyCallback,
        (Action)delegate()
        {
            TokenizeAndSendEmails(emails, tokenizer);
        },
        0,
        sendRepeatedlyDelayMS);
}

private void SendRepeatedlyCallback(object state)
{
    if (!abort)
    {
        Action sendEmails = (Action)state;
        sendEmails();
    }
}

So my question is, is this a flagrant hack? Is there a better or recommended way to do this?

like image 425
Jacobs Data Solutions Avatar asked Nov 23 '11 16:11

Jacobs Data Solutions


2 Answers

As a case you can encapsulate all parameters by a class:

public sealed class SendEmailParameters
{
    public int RepeatCount { get; private set; }
    ...
}

private void SendRepeatedlyCallback(object state)
{
    var parameters = (SendEmailParameters)state;

    // ...
}
like image 122
sll Avatar answered Oct 01 '22 12:10

sll


That's absolutely fine. As of C# 3 I'd use a lambda expression instead, personally - and use a separate local variable to avoid the cast in the middle of a method:

public void SendEmailsRepeatedly(IEnumerable<SimpleEmail> emails,
                                 int sendRepeatedlyDelayMS)
{
    Tokenizer tokenizer = new StandardTokenizer();
    Action action = () => TokenizeAndSendEmails(emails, tokenizer);    
    sendRepeatedlyTimer = new Timer(SendRepeatedlyCallback, action, 0,
                                    sendRepeatedlyDelayMS);
}
like image 37
Jon Skeet Avatar answered Oct 01 '22 12:10

Jon Skeet