0

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());
            }
        }
Houman
  • 64,245
  • 87
  • 278
  • 460

3 Answers3

2
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);
  }
}
Andrew
  • 11,894
  • 12
  • 69
  • 85
Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • Nice sample, but the call to SaveData should really be SaveData(text) -- just a copy/paste leftover, obviously ;-) – Pierre Arnaud Apr 18 '09 at 12:53
  • 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? – Houman Apr 18 '09 at 12:56
  • Just had an idea, would that be the way its done in .NET 2.0 world? ThreadPool.QueueUserWorkItem(delegate { CallBack(customClass, "World"); }); – Houman Apr 18 '09 at 13:02
  • @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 Apr 18 '09 at 13:02
  • @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 Apr 18 '09 at 13:02
  • @Jon But 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) :) – Houman Apr 18 '09 at 13:15
  • @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 Apr 18 '09 at 13:19
  • 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? – Houman Apr 18 '09 at 13:55
  • @Kave: Anonymous methods are just another way of creating delegates. They're like lambdas but slightly clunkier. – Jon Skeet Apr 18 '09 at 16:36
  • @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 Apr 18 '09 at 18:45
  • @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. :) – Houman Apr 18 '09 at 19:38
1

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
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 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 Apr 18 '09 at 13:05
1

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
  • 213,145
  • 36
  • 401
  • 431