Reputation: 787
I found the solution for start thread with arguments with lambda expression.
Thread amazonBuy1 = new Thread(() => amazon.Buy("Lego", visa, dhl));
So, my question is - How exactly does lambda work ? How is it possible to give an method with params where it not possible as default, when speaking of thread argument.
Thank you.
Upvotes: 2
Views: 1038
Reputation: 117064
If we take your call:
Thread amazonBuy1 = new Thread(() => amazon.Buy("Lego", visa, dhl));
...and refactor it into two separate lines we get this:
ThreadStart threadStart = () => amazon.Buy("Lego", visa, dhl);
Thread amazonBuy1 = new Thread(threadStart);
So the constructor to Thread
doesn't take the "Lego"
, visa
, dhl
parameters at all - it simply takes a ThreadStart
delegate.
A delegate is a variable that can be used to invoke a method. In this case the delegate can run amazon.Buy("Lego", visa, dhl)
when invoked.
This means that the thread can start and then call the delegate from inside the new thread.
The compiler does all of the magic to allow visa
and dhl
to get bundled up inside the delegate. This is called a "closure". The compiler produces a delegate that closes over the two variables.
Upvotes: 2
Reputation: 1062905
Allow me to demonstrate what the compiler does there:
class __horribleTypeName {
public Something amazon;
public SomethingElse visa;
public AnotherSomething dhl;
public void __horribleMethodName() {
amazon.Buy("Lego", visa, dhl);
}
}
...
var __horribleLocalName = new __horribleTypeName();
__horribleLocalName.amazon = ... // etc
Thread amazonBuy1 = new Thread(__horribleLocalName.__horribleMethodName);
Make sense? So the lambda contents become the method body of a compiler-generated method. The locals you access inside the body are lifted to fields on the compiler-generated instance. Note that the actual names used here are all "unpronouncable" - they cannot be expressed in C# - they are not legal C# identifiers (but are legal IL identifiers). The above is a simple example - there are other optimizations that the compiler can do in some circumstances, including hoisting things to a reused static delegate instance (when no context is captured). Note also that if visa
or dlh
or amazon
are instance fields, then what you capture is this
, not the fields themselves; so it could be:
class __horribleTypeName {
public YourType __this;
public void __horribleMethodName() {
__this.amazon.Buy("Lego", __this.visa, __this.dhl);
}
}
...
var __horribleLocalName = new __horribleTypeName();
__horribleLocalName.__this = this;
Thread amazonBuy1 = new Thread(__horribleLocalName.__horribleMethodName);
As a side note: if you want to pass in state to a thread, there is a ParameterizedThreadStart
.
Upvotes: 4
Reputation: 2950
A lambda expression is an anonymous function and it is mostly used to create delegates in LINQ. Simply put, it's a method without a declaration, i.e., access modifier, return value declaration, and name. Convenience. It's a shorthand that allows you to write a method in the same place you are going to use it.
Source: https://msdn.microsoft.com/en-GB/library/bb397687.aspx
Your Thread
takes a delegate called ThreadStart
or ParameterizedThreadStart
. So when you use lambda like this, you're creating the delegate method on the fly.
Upvotes: 0