13.07.2015 Views

C# in Depth

C# in Depth

C# in Depth

SHOW MORE
SHOW LESS
  • No tags were found...

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Captur<strong>in</strong>g variables <strong>in</strong> anonymous methods153Console.WriteL<strong>in</strong>e (captured);captured = "before second <strong>in</strong>vocation";x();The output of list<strong>in</strong>g 5.11 is as follows:directly before x is <strong>in</strong>vokedchanged by xbefore second <strong>in</strong>vocationLet’s look at how this happens. First, we declare the variable captured and set its valuewith a perfectly normal str<strong>in</strong>g literal. So far, there’s noth<strong>in</strong>g special about the variable.We then declare x and set its value us<strong>in</strong>g an anonymous method that capturescaptured. The delegate <strong>in</strong>stance will always pr<strong>in</strong>t out the current value of captured,and then set it to “changed by x”.Just to make it absolutely clear that just creat<strong>in</strong>g the delegate <strong>in</strong>stance didn’t readthe variable and stash its value away somewhere, we now change the value of capturedto “directly before x is <strong>in</strong>voked”. We then <strong>in</strong>voke x for the first time. It reads the valueof captured and pr<strong>in</strong>ts it out—our first l<strong>in</strong>e of output. It sets the value of captured to“changed by x” and returns. When the delegate <strong>in</strong>stance returns, the “normal”method cont<strong>in</strong>ues <strong>in</strong> the usual way. It pr<strong>in</strong>ts out the current value of captured, giv<strong>in</strong>gus our second l<strong>in</strong>e of output.The normal method then changes the value of captured yet aga<strong>in</strong> (this time tobefore second <strong>in</strong>vocation) and <strong>in</strong>vokes x for the second time. The current value ofcaptured is pr<strong>in</strong>ted out, giv<strong>in</strong>g our last l<strong>in</strong>e of output. The delegate <strong>in</strong>stance changescaptured to changed by x and returns, at which po<strong>in</strong>t the normal method has run outof code and we’re done.That’s a lot of detail about how a pretty short piece of code works, but there’s reallyonly one crucial idea <strong>in</strong> it: the captured variable is the same one that the rest of the methoduses. For some people, that’s hard to grasp; for others it comes naturally. Don’t worry ifit’s tricky to start with—it’ll get easier over time. Even if you’ve understood everyth<strong>in</strong>geasily so far, you may be wonder<strong>in</strong>g why you’d want to do any of this. It’s about time wehad an example that was actually useful.5.5.3 What’s the po<strong>in</strong>t of captured variables?To put it simply, captured variables get rid of the need for you to write extra classesjust to store the <strong>in</strong>formation a delegate needs to act on, beyond what it’s passed asparameters. Before ParameterizedThreadStart existed, if you wanted to start a new(non-threadpool) thread and give it some <strong>in</strong>formation—the URL of a page to fetch,for <strong>in</strong>stance—you had to create an extra type to hold the URL and put the action ofthe ThreadStart delegate <strong>in</strong>stance <strong>in</strong> that type. It was all a very ugly way of achiev<strong>in</strong>gsometh<strong>in</strong>g that should have been simple.As another example, suppose you had a list of people and wanted to write amethod that would return a second list conta<strong>in</strong><strong>in</strong>g all the people who were under agiven age. We know about a method on List that returns another list of everyth<strong>in</strong>gmatch<strong>in</strong>g a predicate: the F<strong>in</strong>dAll method. Before anonymous methods and capturedLicensed to Rhona Hadida

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!