Showing posts with label Delegate. Show all posts
Showing posts with label Delegate. Show all posts

Thursday, August 6, 2009

Getting data back from a thread

How do you get data back from a thread if you don't know when it'll finish running? You do it by using a delegate. When the code in the thread is complete, it'll call a delegate that is referenced back at the originating code.

Here are the basic steps:
  1. Define a delegate.
  2. public delegate void ReturnResult(object sender);
  3. In the class that contains the method to be called, create a field/property of your new delegate.
  4. public ReturnResult ReturnResultDelegate;
  5. In the class that starts the thread, define a method that matches your delegate's signature. This is the method that will be receiving the callback from the thread.
  6. static void CheckReturnedResult(object sender)
    {
        Math m = (Math) sender;
        Console.WriteLine("Result:" + m.Result);
    }
  7. Instantiate the class and set your delegate to the method you created.
  8. Math math = new Math();
    math.Value1 = 1;
    math.Value2 = 3;
    math.ReturnResultDelegate = CheckReturnedResult;
  9. Have your class call the delegate somewhere when the thread runs.
  10. public void Add(object o)
    {
        Result = Value1 + Value2;
        ReturnResultDelegate(this);
    }
Optionally, you can send just the return result back instead of the whole class.
Let's put everything together and see how it all works in this console application:
using System;
using System.Threading;

namespace ThreadingApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Math math = new Math();
            math.Value1 = 1;
            math.Value2 = 3;
            math.ReturnResultDelegate = CheckReturnedResult;

            ThreadPool.QueueUserWorkItem(math.Add);
            Thread.Sleep(1000);
        }

        static void CheckReturnedResult(object sender)
        {
            Math m = (Math)sender;
            Console.WriteLine("Result:" + m.Result);
        }
    }

    public class Math
    {
        public int Value1;
        public int Value2;
        public int Result;
        public delegate void ReturnResult(object sender);

        public ReturnResult ReturnResultDelegate;

        public void Add(object o)
        {
            Result = Value1 + Value2;
            ReturnResultDelegate(this);
        }
    }
}
In this sample, I minimize the scope of the delegate by including it in the class being called (Math). You might declare it outside the class if needed.

Thursday, April 24, 2008

Predicate Delegate

To pose a problem, let's create a strongly typed list of the Person class:
public class Person
{
    public string FirstName { get; set; }
}

// ...

List<Person> people = new List<Person>
              {
                  new Person("Mark"),
                  new Person("Rod"),
                  new Person("Matt"),
                  new Person("Rich"),
                  new Person("Jake")
              };
I used a collection initializer to populate a new typed generic List.

Ok, so how would you do a search in that collection and return the Person class that represents "Rod"? Luckily this generic list class has 5 different Find type methods (9 if you count the overloads).

Take a look at them though. They take a "Predicate". What the heck is this "Predicate"?

The word "predicate" is a term used in the subject of Logic that basically means
"to say something is true or false"
.

A predicate in .NET is a delegate that represents a method you write to check if a condition is true or false. So your predicate method will take in one parameter, evaluate it, and then return a true or false. Let's see what this might look like:
// Your predicate function.
private bool FindRod(Person person)
{
    if (person.FirstName == "Rod")
        return true;
    return false;
}

// ...

Person foundPerson = people.Find(FindRod);
Now when you call the Find method, just pass in the name of your predicate method. The Find method will loop through all the items in the collection and run your predicate method until a true is returned.

Now that you have the basics down, I think you can take a look at the other Find methods and be able to tell what they do.

More Info: MSDN: Predicate(T) Generic Delegate

Wednesday, April 23, 2008

Delegates

The word "delegate" means "to represent another". A delegate in .NET is just another type, like class or string is a type. A delegate "represents another" method. I'll give examples of using a delegate next to a class so you can see some similarities in how they are used.

Declaring
// 1. Declare it.
public delegate int PerformCalculation(int x, int y);
public class Person
{
    public string GetName()
    {
        return "Mark";
    }
}
So it is like declaring any other type except instead of a variable name, you will be using a method signature. The method name (PerformCalculation) is how you reference the delegate.
You declare the variable "PerformCalculation" as the type "delegate". Think of it as defining a method signature (just like you would in an interface) and then putting the word "delegate" in front of it.

Assigning a Value
public void CreateAndUse()
{
    // 2. Assign a value.
    PerformCalculation calc = AddNumbers;
    Person person = new Person();
}

public int AddNumbers(int number1, int number2)
{
    return number1 + number2;
}
See how methods, like AddNumbers, are treated just like objects here? I assign it to my PerformCalculation delegate type. Make sure the signatures are similar.

Using It
// 3. Use it.
int sum = calc(1, 2);
string name = person.GetName();
Remember, your delegate is used to "represent another" method. So when you go to use it, you use it (call it) like a method.

Passing It
Like any object, you can pass it into methods or return it from methods. Here is an example of passing it into a method:
// 4. Pass it.
calc = SubtractNumbers;
string result = CalculateFreeSpace(calc, person);

//...

private int SubtractNumbers(int number1, int number2)
{
    return number1 - number2;
}

private string CalculateFreeSpace(PerformCalculation calc, Person person)
{
    int maxLength = 50;
    int freeSpace = calc(maxLength, person.GetName().Length);
    return string.Format("Free Space Left: {0}", freeSpace);
}
Before I passed as a parameter into the CalculateFreeSpace method, I decided to have it represent a different method with a similar signature.
Pretty interesting, huh? Here, I am injecting customized functionality into the method.
This opens up possibilities to you. You can use this as a way of doing your unit testing. Perhaps the delegate you pass in really calls a SQL Server. So before your unit test calls the method to be tested, you create your delegate to return a hard-coded result instead of calling your SQL Server.

I will be talking more about delegates tomorrow as well.

More Info: MSDN: Delegates