views:

92

answers:

3

I have a fairly generic class (Record) that I have added a callback handler to, so I can do something like the following.

record.Save(AfterSaveMethod);

Which also returns the identity number of the record created. The issue I have now is that I have this nested save routine in a loop, and I need to use/pass the i variable!

for (int i; i < count ;i++)
{
    record.Save(AfterSaveMethod2) //but I need to pass i through as well
}  

What do I do here?

A\ rewrite the save method and include it in this class (yuk),

B\ have an overloaded save option that takes an object as a parameter, so I can pass it through to my record class, and then merge it with the identity number. Returning both the identity number and anything extra contained in the passed through object (hmm, sounds a bit messy),

C\ is there a sexier option?

+6  A: 

This is where anonymous methods or lambda expressions are really handy :)

Try this (assuming C# 3):

for (int i = 0; i < count; i++)
{
    int index = i;
    record.Save(id => AfterSaveMethod2(id, index));
}

Note that the lambda expression here is capturing index, not i - that's to avoid the problems inherent in closing over the loop variable.

Jon Skeet
A very elegant solution, Mr. Skeet!
decyclone
ok, makes sense, just need to sort out the foo ;) Action<int> is my delegate type
Grayson Mitchell
@Grayson: So what is the integer that it gets passed?
Jon Skeet
The integer is the identity number returned by the WCF service. So in this case I save a record, and then on completion I save another record that is the child of that record, so I need the identity number from the first record. (plus the index)
Grayson Mitchell
Okay, so it's the identity value - I'll adjust my code appropriately :)
Jon Skeet
thanks man, that works... now I have to add some threading, as my 'AfterSaveMethod2' does not get called until the UI thread is processed.
Grayson Mitchell
A: 
    class SexierSaveMethod
    {
        public Int32 Index { get; set; }

        public SexierSaveMethod(Int32 i)
        {
            Index = i;
        }

        public void AfterSaveMethod()
        { 
            // Use i here
        }
    }

    record.Save(new SexierSaveMethod(i).AfterSaveMethod);
decyclone
+2  A: 

You could also create a (thread-static) context object, which stores your "state" (in this case, the index variable value), which you can access using a static property (say MyContext.Current). Depends on the complexity of the context ...

WCF uses something like this with OperationContext.Current, ASP.NET, TransactionScope et al.

If the context is a bit more complex than yours and you don't want to pollute the signatures of several methods, I think this model is quite neat.

Use:

// init context
MyContext.Current = new MyContext();
for (var idx = 0; idx < 99; idx++) {
    MyContext.Current.Idx = idx;
    record.Save(AfterSaveMethod);        

}
// uninitialize context
MyContext.Current = null;

(very simplistic sample)

If the context is [ThreadStatic] you could have multiple concurrent calls which won't affect each other

funky, this looks nice also
Grayson Mitchell