views:

149

answers:

2

Is there a way I can inline the delegated task instead of separating it on another function?

Original Code:

    private void ofdAttachment_FileOk(object sender, CancelEventArgs e)
    {            
        System.Threading.ThreadPool.QueueUserWorkItem((o) => Attach());
    }

    void Attach() // I want to inline this function on FileOk event
    {

        if (this.InvokeRequired)
        {
            this.Invoke(new Action(Attach));
        }
        else
        {
            // attaching routine here
        }
    }

I wanted it to be like this(no need to create a separate function):

    private void ofdAttachment_FileOk(object sender, CancelEventArgs e)
    {

        Action attach = delegate
        {
            if (this.InvokeRequired)
            {
                // but it has compilation here
                // "Use of unassigned local variable 'attach'"
                this.Invoke(new Action(attach)); 
            }
            else
            {
                // attaching routine here
            }
        };

        System.Threading.ThreadPool.QueueUserWorkItem((o) => attach());
    }
+1  A: 

I think this will work:

private void ofdAttachment_FileOk(object sender, CancelEventArgs e)
{

    Action attach = null;
    attach = delegate
    {
        if (this.InvokeRequired)
        {
            // since we assigned null, we'll be ok, and the automatic
            // closure generated by the compiler will make sure the value is here when
            // we need it.
            this.Invoke(new Action(attach)); 
        }
        else
        {
            // attaching routine here
        }
    };

    System.Threading.ThreadPool.QueueUserWorkItem((o) => attach());
}

All you need to do is assign a value to 'attach' (null works) before the line that declares the anonymous method. I do think the former is a bit easier to understand though.

Jonathan
thanks, that works ^_^ it's just a bit befuddling, why C# detected it as unassigned
Hao
At runtime, the right-hand side of the assignment is evaluated before the left-hand side. Therefore, the part of the compiler responsible for this warning probably sees that we're trying to use the variable's value within the right-hand side of the expression on the line we assign it, hence, during the evaluation of the RHS, it hasn't been assigned yet. Of course, since the compiler is going to lift it out into a closure, it would be ok anyway -- I guess the compiler isn't aware of how it's going to modify it when it emits the warning.
Jonathan
A: 

The reason you get the "use of unassigned variable" error is because of the way the compiler actually generates the code. When you use the delegate{} syntax a real method is created for you by the compiler. Since you're referencing the attached field in your delegate, the compiler attempts to pass the local variable attach to the generated delegate method.

Here's the roughly translated code which should help make it clearer:

private void ofdAttachment_FileOk(object sender, CancelEventArgs e)
{

 Action attach = _b<>_1( attach );

 System.Threading.ThreadPool.QueueUserWorkItem((o) => attach());
}

private Action _b<>_1( Action attach )
{
 if (this.InvokeRequired)
 {
  // but it has compilation here
  // "Use of unassigned local variable 'attach'"
  this.Invoke(new Action(attach)); 
 }
 else
 {
  // attaching routine here
 }
}

Notice that it's passing the attach field to the _b<>_1 method before it's initialized.

Paul Alexander