Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / July 2008

Tip: Looking for answers? Try searching our database.

Captured variables

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Peter Morris - 21 Jul 2008 11:16 GMT
var result = new List<StockLevelRow>();
foreach(SomeClass c in SomeList)
   result.Add(
       new StockLevelRow(c.Name,
           delegate() { return c.StockLevel; },
           delegate(int value) { c.StockLevel = value; }
       )
   );

This is a PITA because the last variable assigned to "c" is captured by each
of the two delegates.  Is there a simple workaround for this?  If not then I
am going to have to make my StockLevelRow class abstract and create a
concrete descendant for each different way I have of obtaining/setting the
StockLevelRow.Quantity (which currently uses a get and set delegate passed
to it).

Thanks

Pete
Jon Skeet [C# MVP] - 21 Jul 2008 11:30 GMT
> var result = new List<StockLevelRow>();
> foreach(SomeClass c in SomeList)
[quoted text clipped - 11 lines]
> StockLevelRow.Quantity (which currently uses a get and set delegate passed
> to it).

Copy the variable:

var result = new List<StockLevelRow>();
foreach(SomeClass c in SomeList) {
   SomeClass copy = c;
   result.Add(
       new StockLevelRow(copy.Name,
           delegate() { return copy.StockLevel; },
           delegate(int value) { copy.StockLevel = value; }
       )
   );
}

Jon
Peter Morris - 21 Jul 2008 16:12 GMT
I decided to keep the original + more complicated code that already existed
(descendant classes) for now.  I will remember your tip for next time I need
it, thanks! :-)
Peter Duniho - 21 Jul 2008 16:43 GMT
> var result = new List<StockLevelRow>();
> foreach(SomeClass c in SomeList)
[quoted text clipped - 7 lines]
> This is a PITA because the last variable assigned to "c" is captured by  
> each of the two delegates.  Is there a simple workaround for this?

For what it's worth, if you think this "is a PITA", it's my opinion you're  
looking at it the wrong way.

The variable capturing rules are the way the are for consistency, and if  
it _didn't_ work that way, it could be a genuine "PITA" for other  
scenarios.

I do wonder if what you're doing wouldn't be better addressed using an  
interface that defines the property you seem to be implementing via  
anonymous methods here, but that's a different question altogether.  :)

Pete
Peter Morris - 21 Jul 2008 17:28 GMT
It's a PITA if it is causing me a PITA.  Whether or not it is supposed to
cause me a PITA is irrelevant :-)

I do wonder if what you're doing wouldn't be better addressed using an
interface that defines the property you seem to be implementing via
anonymous methods here, but that's a different question altogether.  :)
<<

I agree that it is more like an interface and to be "more proper" should be
implemented as an interface.  However, this would result in the same thing,
lots of subclasses :-)  I am basically binding a reusable GUI "Record Stock
Levels" to different classes, so this is acting like a mediator.

Case 1:
Quantity maps to StockCheck.QuantityOnHand

Case 2:
Quantity maps to Replenishment.QuantityAdded

Case 3:
Quantity maps to Replenishment.OpeningLevel

and so on, there are about 6 cases.  I just thought having a single class
with delegates for Get/Set quantity would be easier than having to write a
mediator for each class.  I don't want to add an interface to StockCheck etc
because the interface would be for GUI purposes only, and I don't like
adding GUI specific stuff to my business classes, it's a PITA ;-)

Knowing that a local variable will do the trick is useful information that I
will put to good use in future.

Pete
Pavel Minaev - 21 Jul 2008 19:44 GMT
On Jul 21, 7:43 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> The variable capturing rules are the way the are for consistency, and if  
> it _didn't_ work that way, it could be a genuine "PITA" for other  
> scenarios.

To be honest, I can hardly come up with a scenario where the existing
rule for capturing of the foreach variable (or rather, the rule for
the scoping of that variable seen in context of capturing) would be
useful. I wonder why they didn't just move the declaration of the
variable in foreach expansion inside the loop body when they
introduced closures in 2.0.
Peter Duniho - 21 Jul 2008 19:59 GMT
> To be honest, I can hardly come up with a scenario where the existing
> rule for capturing of the foreach variable (or rather, the rule for
> the scoping of that variable seen in context of capturing) would be
> useful. I wonder why they didn't just move the declaration of the
> variable in foreach expansion inside the loop body when they
> introduced closures in 2.0.

You'd have to ask the designers to know for sure.  However, it seems to me  
that there's value in having the "for" loop consistent with the "foreach"  
loop, and obviously the "for" loop _must_ not have variables declared in  
the statement created anew with each iteration of the loop.

As far as I know, the "foreach" variable never depends on its previous  
value; it's always just being reassigned from the enumerator.  But  
changing the scoping semantics of "foreach" would make it inconsistent  
with the rest of the language.  If nothing else, that's inelegant, and it  
could in fact lead to more manifestations of the variable-capturing error,  
in the context of "for" loops (i.e. a programmer could incorrectly infer  
that capturing a "for" iteration variable would work the same as capturing  
a "foreach" iteration variable).

Pete
Jon Skeet [C# MVP] - 21 Jul 2008 19:59 GMT
> On Jul 21, 7:43 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
> wrote:
[quoted text clipped - 8 lines]
> variable in foreach expansion inside the loop body when they
> introduced closures in 2.0.

Indeed - especially as the natural way of reading "for each int i" is
that there are multiple "i" variables. On the other hand, that would be
inconsistent with "for" (which really does only declare variables
once).

Signature

Jon Skeet - <skeet@pobox.com>
Web site: http://www.pobox.com/~skeet   
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.