15

I somehow feel I am missing something basic. Here's my problem.

I am trying to create a System.Threading.Tasks.Task instance to execute an action that accepts a parameter of a certain type. I thought I could do something like

void DoWork(MyClass obj) {} //My action that accepts a parameter of type 'MyClass'

MyClass obj = new MyClass(); 
Action<MyClass> action = DoWork; //action that points to the method
Task task = new Task(action,obj); //task that would execute 'DoWork' with 'obj' as the parameter when I call Start.

Obviously this does not compile. It seems I can only use an Action<object> and not an Action<T> for a task and then cast the 'object' to T inside my method.

How can I achieve what I want most effectively and efficiently?

alwayslearning
  • 4,493
  • 6
  • 35
  • 47

2 Answers2

10

You also can use directly:

MyClass obj = new MyClass();
Task task = Task.Run(() => DoWork(obj));
cuongle
  • 74,024
  • 28
  • 151
  • 206
  • 2
    Just to mention: This has a slightly different meaning. If you change the *variable* `obj` before starting the task, or even just before the `Task` logic called the delegate, `DoWork` will work on the new object. This can lead to bugs which are very hard to track. A classic situation would be, if you use this inside a loop `foreach(MyClass o in myObjList) { (new Task(()=>DoWork(o))).Start(); }`. – MartinStettner Oct 26 '12 at 06:45
  • @MartinStettner, _"A classic situation would be, if you use this inside a loop"_ foreach loop has been changed and now such code is correct. – Qwertiy Jul 27 '16 at 19:45
6

You could use

Action<Object> action = o => DoWork((MyClass)o);
Task task = new Task(action, obj);

If you're using .NET 4.0 or above, you can use Contravariance to achieve your goal without introducing a new delegate

//INCORRECT Code, casts InvalidCastException at runtime
Action action = DoWork;
Task task = new Task((Action)action, obj);

EDIT:

Thanks for @svick for pointing out, that the second option is not correct: I was too busy sorting out, whether Action is co- or contravariant (it is in fact contravariant, I was right about this at least) that I oversaw, that I would need Covariance in this case.

Contravariance means that you can do

Action<object> action1 = someAction;
Action<SubClass> action2 = action1;

without explicit casting.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
MartinStettner
  • 28,719
  • 15
  • 79
  • 106