views:

239

answers:

3

Hello everyone,

I am a bit new to ThreadPool in .NET. I was wondering, if I can only send one object to my callback method, how am I able to access the class member variable to call its methods? (see customClass in CallBack())

And how would I load the data from customClass? Do I pass the customClass to a different CallBack method? is this approach alright?

As you can see it is a bit of lack of experience, so any tips along the way would really be appreciated.

Thank you, Kave

class Program
           {
                static void Main(string[] args)
                {
                    CustomClass customClass = new CustomClass();

                ThreadPool.QueueUserWorkItem(CallBack, "Hello"); 


                Console.Read();
            }

            private static void CallBack(object state)
            {
                customClass.SaveData(state.ToString());
            }
        }
+1  A: 

The easiest way to do this is to use a closure to capture all the variables you want (i.e. use an anonymous method or a lambda expression). You need to be careful about exactly what's captured if you're using a loop, but it's handier than passing through an object and having to cast it back to the right type etc.

Jon Skeet
To clarify, the reason care needs to be taken in loops with closure is addressed in this question: http://stackoverflow.com/questions/271440/c-captured-variable-in-loop
Greg D
+2  A: 
class Program
{
  static void Main(string[] args)
  {
    CustomClass customClass = new CustomClass();
    ThreadPool.QueueUserWorkItem(x => CallBack(customClass, "Hello")); 
    Console.Read();
  }

  private static void CallBack(CustomClass custom, string text)
  {
    customClass.SaveData(text);
  }
}
Stefan Steinegger
Nice sample, but the call to SaveData should really be SaveData(text) -- just a copy/paste leftover, obviously ;-)
Pierre
wow very nice example! With .NET 3.5 there is no need for CallBack methods having object as parameter anymore is this correct?I would also highly appreciate a .NET 2.0 solution to this problem, so I know both ways. Any idea?
Kave
Just had an idea, would that be the way its done in .NET 2.0 world?ThreadPool.QueueUserWorkItem(delegate { CallBack(customClass, "World"); });
Kave
@Kave: See the article linked in my answer. Instead of using a lambda expression, use an anonymous method.@Stefan: Why bother with the "Callback" method at all? Just write: x => customClass.SaveData("Hello")
Jon Skeet
@Kave: Yes, that's the way you do it in C# 2. Note that you can use lambda expressions with C# 3 even if you're targeting .NET 2.0. It's a language feature, not a framework feature.
Jon Skeet
@JonBut in order to compile the code .NET 3.5 must be installed, isn't it? I don't think you can compile lamda expressions on dev environments with .NET 2.0 only. regarding anonymous method, wouldn'y a delegate be doing the same job? (I admit I dont know about anonymous methods yet) :)
Kave
@Kave, yes, you need Visual Studio 2008 or the .NET 3.5 SDK as a developer. Your users only would need .NET 2.0, though.
Erv Walter
One more question came up, what if my Callback method is returning an integer. How would the caller from main method get that integer back?
Kave
@Kave: Anonymous methods are just another way of creating delegates. They're like lambdas but slightly clunkier.
Jon Skeet
@Kave:1. in .Net 2.0, I think you need to cast the delegate, or use the new operator: ThreadPool.QueueUserWorkItem((WaitCallback)delegate { CallBack(customClass, "World"); }); I'm not even sure if this would work. x => Foo() actually generate a delegate with an argument x, that is not used in this case. It's this "object state" argument that is required.2. You can't return anything from a thread. It is an asynchronous call, isn't it? But of course you can return values from lambdas.
Stefan Steinegger
@Jon Thanks.@Stefan, also thanks for explanation. Your delegate is correct and would work. Regarding 2) you are right. And yet I think only the Backgroundworker can do this though. Amazing no one takes that poor Backgroundworker seriously, yet it is kind of powerful. :)
Kave
+1  A: 

In addition to what has been said: If CustomClass is under your control and asynchronously invoking SaveData is a common use case, you could think about providing a SaveDataAsync method:

class CustomClass {

    public void SaveDataAsync(string path) {
        ThreadPool.QueueUserWorkItem(state => this.SaveData(path));
    }

    public void SaveData(string path) {
        ...
    }
}

See the Event-based Asynchronous Pattern.

dtb
Thats a very nice tip. Thank you very much.
Kave