1

Consider use case: I need to pass a parameter to QueueUserWorkItem:

ThreadPool.QueueUserWorkItem((o) =>
{
    var item = o as MyObject;
},
item);

Then requirements changed and I now need to pass 2 objects. So I would have to write something like:

ThreadPool.QueueUserWorkItem((o) =>
{
    var items = o as Tuple<MyObject,MyObject2>;
},
new Tuple<MyObject,MyObject2>(item1, item2));

Is there a cleaner way to achieve this in C# 9+ ?

Boppity Bop
  • 9,613
  • 13
  • 72
  • 151

2 Answers2

2

You can use this overload if your target framework has it. Then you can do:

ThreadPool.QueueUserWorkItem(args => {
    var first = args.Item1; // it's of type string already
    var second = args.Item2; // this is int
}, ("a", 1), false);

Or:

ThreadPool.QueueUserWorkItem(args => {
    var first = args.first; // it's of type string already
    var second = args.second; // this is int
}, (first: "a", second: 1), false); // name parameters here instead of using Item1 Item2

And in single parameter case you don't need to cast type from object (this overload accepts generic Action<T> delegate).

Evk
  • 98,527
  • 8
  • 141
  • 191
0

You can always leverage closures in C# lambdas and ingore passing parameter completely:

var item1 = ...;
var item2 = ...;
ThreadPool.QueueUserWorkItem(_ =>
{
    Console.WriteLine(item1);
    Console.WriteLine(item2);
});

Also personally I would consider switching to Task.Run instead of ThreadPool.QueueUserWorkItem (though there should be some considiration due to some differences in behaviour).

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • I always thought that in this case item1/2 in the outer scope can be tainted by another thread cutting in between.. this is why i actually am passing the object as a parameter rather than using it inside the delegate.. can you provide definitive proof its not the case? – Boppity Bop Oct 18 '21 at 18:44
  • @BoppityBop it depends on what do you mean by "tainted" and "another thread cutting in between". AFAIK you can have only the usual problems with closures - if local variable is modified after being captured by the action (the infamous [for/foreach closure behaviour difference after C# 5](https://stackoverflow.com/q/35365350/2501279)). – Guru Stron Oct 18 '21 at 19:21
  • yes - I am passing object as a param instead of using closures because I am convinced that its value can be modified in another thread before it is used in this thread.. so in short words - I want solution without using closures.. Ill edit the question. – Boppity Bop Oct 19 '21 at 10:03
  • @BoppityBop can you please share some code that can have such problem? Also i hugely depends on what `item1` and `item2` are and how they are used. – Guru Stron Oct 19 '21 at 11:38