Passing in an anonymous delegate to a thread...why does this work?
Asked Answered
L

3

6

In my program, we split up a large amount of data that needs to be looked over across four threads.

Thread one = new Thread(delegate() { NewMethod(recordsSplitIntoQuarters[0], param2, param3, param4, param5); });
Thread two = new Thread(delegate() { NewMethod(recordsSplitIntoQuarters[1], param2, param3, param4, param5); });
Thread three = new Thread(delegate() { NewMethod(recordsSplitIntoQuarters[2], param2, param3, param4, param5); });
Thread four= new Thread(delegate() { NewMethod(recordsSplitIntoQuarters[3], param2, param3, param4, param5); });

Our coding standards require that we are StyleCop compliant, as it were, and StyleCop demands the following:

SA1410: Remove the parenthesis from the anonymous method, since the delegate's parameter list is empty.

Doing that gives me this compiler error:

The call is ambiguous between the following methods or properties: 'System.Threading.Thread.Thread(System.Threading.ParameterizedThreadStart)' and 'System.Threading.Thread.Thread(System.Threading.ThreadStart)'

I've looked into the ThreadStart and ParameterizedThreadStart objects and I just can't figure out how to get what I need done with either of those objects.

My question: how do the anonymous delegates work? What do they compile down to? In the end, I will have to get this working without the anonymous delegates, but I don't know where to begin.

Thanks for the help,

Seeker

Lanfri answered 30/11, 2010 at 20:48 Comment(0)
G
7

You have two options:

  • Ignore the StyleCop warning (recommended)
  • Change it to new ThreadStart(delegate { ... })

Explanation:

An anonymous method without parentheses (delegate { ... }) has an implicit parameter list. The compiler will give it whatever parameters are needed to match the delegate it's being used as. (Your code cannot see the parameters)
This is very useful when writing anonymous event handlers that don't use their parameters; it saves you from typing delegate(object sender, EventArgs e) { ... }.

However, when calling the Thread constructor, there are two different overloads that take two kinds of delegates.
The compiler has no way of knowing which delegate type you're trying to create, since you didn't specify a parameter list.

Geodetic answered 30/11, 2010 at 20:50 Comment(1)
From your description that style-cop rules sounds like a stupid idea in general. And it's description of "When an anonymous method does not contain any method parameters, the parenthesis around the parameters are optional." would be misleading too.Heaps
C
5

StyleCop is dumb.

StyleCop is implying that the two syntaxes have the same meaning. This is completely wrong. Omitting the parentheses from a delegate does not mean "this takes no arguments." It means "fill in any arguments for me, because I won't be using them anyway."

Since two different signatures of Thread:.ctor are available, each taking a different delegate type, the compiler cannot know which one to pick, since it would be just fine with either one. Adding the parentheses forces the compiler to pick the ThreadStart variant, since it is the only signature with a delegate type compatible with your anonymous method.

If you want to make StyleCop happy and have your code compile, this is one option:

Thread one = new Thread(new ThreadStart(delegate { NewMethod(recordsSplitIntoQuarters[0], param2, param3, param4, param5); }));

This is another:

Thread one = new Thread((ThreadStart) delegate { NewMethod(recordsSplitIntoQuarters[0], param2, param3, param4, param5); });

But my suggestion would be to LART the StyleCop authors for introducing this ridiculous rule.

Conferva answered 30/11, 2010 at 20:52 Comment(3)
Note that both options will (AFAIK) compile identically.Geodetic
Yes, they will. The latter syntax effectively uses the syntactic sugar introduced in C# 2 that allows the omission of the new DelegateType(...) construct when the delegate type can be inferred from the context. The cast supplies the necessary context.Conferva
Can somebody with a codeplex account post this in their forum?Heaps
M
3

You could use a lambda expression instead of the delegate keyword:

Thread one = new Thread(() => NewMethod(recordsSplitIntoQuarters[0], param2, param3, param4, param5));
Merge answered 30/11, 2010 at 20:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.