Passing a method parameter using Task.Factory.StartNew

129,321

Solution 1

The best option is probably to use a lambda expression that closes over the variables you want to display.

However, be careful in this case, especially if you're calling this in a loop. (I mention this since your variable is an "ID", and this is common in this situation.) If you close over the variable in the wrong scope, you can get a bug. For details, see Eric Lippert's post on the subject. This typically requires making a temporary:

foreach(int id in myIdsToCheck)
{
    int tempId = id; // Make a temporary here!
    Task.Factory.StartNew( () => CheckFiles(tempId, theBlockingCollection),
         cancelCheckFile.Token, 
         TaskCreationOptions.LongRunning, 
         TaskScheduler.Default);
}

Also, if your code is like the above, you should be careful with using the LongRunning hint - with the default scheduler, this causes each task to get its own dedicated thread instead of using the ThreadPool. If you're creating many tasks, this is likely to have a negative impact as you won't get the advantages of the ThreadPool. It's typically geared for a single, long running task (hence its name), not something that would be implemented to work on an item of a collection, etc.

Solution 2

class Program
{
    static void Main(string[] args)
    {
        Task.Factory.StartNew(() => MyMethod("param value"));
    }

    private static void MyMethod(string p)
    {
        Console.WriteLine(p);
    }
}

Solution 3

For passing a single integer I agree with Reed Copsey's answer. If in the future you are going to pass more complicated constucts I personally like to pass all my variables as an Anonymous Type. It will look something like this:

foreach(int id in myIdsToCheck)
{
    Task.Factory.StartNew( (Object obj) => 
        {
           var data = (dynamic)obj;
           CheckFiles(data.id, theBlockingCollection,
               cancelCheckFile.Token, 
               TaskCreationOptions.LongRunning, 
               TaskScheduler.Default);
        }, new { id = id }); // Parameter value
}

You can learn more about it in my blog

Solution 4

Construct the first parameter as an instance of Action, e.g.

var inputID = 123;
var col = new BlockingDataCollection();
var task = Task.Factory.StartNew(
    () => CheckFiles(inputID, col),
    cancelCheckFile.Token,
    TaskCreationOptions.LongRunning,
    TaskScheduler.Default);

Solution 5

Try this,

        var arg = new { i = 123, j = 456 };
        var task = new TaskFactory().StartNew(new Func<dynamic, int>((argument) =>
        {
            dynamic x = argument.i * argument.j;
            return x;
        }), arg, CancellationToken.None, TaskCreationOptions.AttachedToParent, TaskScheduler.Default);
        task.Wait();
        var result = task.Result;
Share:
129,321
Jon
Author by

Jon

Updated on July 05, 2022

Comments

  • Jon
    Jon almost 2 years

    I have the following code:

    var task = Task.Factory.StartNew(CheckFiles, cancelCheckFile.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
    
    private void CheckFiles()
    {
      //Do stuff
    }
    

    I now want to amend CheckFiles to accept and integer and a BlockingCollection reference

    private void CheckFiles(int InputID, BlockingCollection<string> BlockingDataCollection)
    {
      //Do stuff
    }
    

    I can't seem to find a way to Start this task as I did above.

    Can you help?

    Thanks

  • Jon
    Jon over 12 years
    Thanks. I will be starting them in a loop. However I do need it as LongRunning. My original program worked with one file but now it needs to do some code on numerous files. Therefore I need to pass in the ID, BlockingCollection, CancellationTokenSoure and StreamReader. I didnt add those extra method parameters in the question however
  • Reed Copsey
    Reed Copsey over 12 years
    @Jon: Just make sure to check the scope of those objects... I just mentioned the LongRunning hint as something for you to consider - I will say that its rarely a good idea to use LongRunning, especially in .NET 4, if you're starting many tasks (ie: working in a loop), as the threadpool will typically provide better behavior.
  • Jon
    Jon over 12 years
    The loop is just to start the tasks. Maximum of 4-6
  • Adam Ralph
    Adam Ralph over 12 years
    I second Reed's comment about LongRunning. I'd be surprised if you see benefit from passing this argument rather than cost.
  • Jon
    Jon over 12 years
    Are you suggesting that I manually create the threads myself? The tasks are long running.
  • Reed Copsey
    Reed Copsey over 12 years
    @Jon No, I'd use tasks, but not flag them long running unless you really need to do so. By default, a Task uses a ThreadPool thread. If you flag them "LongRunning", with the default TaskScheduler, you'll get a dedicated thread made just for that task instead. This is usually not necessary, and, if working with many tasks, bypasses all of the goodness of the ThreadPool, which can impact the behavior of child tasks, etc...