views:

500

answers:

8

Background

Given that 'most' developers are Business application developers, the features of our favorite programming languages are used in the context of what we're doing with them.

As a C# / ASP.NET Application developer, I tend to only use delegates when dealing with UI events. In fact (and this is part of my inexperience showing), I don't even know a good context other than events to use delegates in! This is quite scary; but I'm gathering that there are other developers in the same boat.

NB: Answers should pertain to .NET 2.0. .NET 3.0 takes delegates to a different level entirely, and that'll likely be a separate question.

Question:

Besides events, how useful are delegates, and in what Business Application contexts are they most useful?

Update: Jarrod Dixon helpfully linked to the MSDN documentation regarding delegate usage, and I must admit that my favorite Design Patterns Book didn't bring up delegates at all, so I haven't really seen them in use other than for UI events. To expand this question (just a little bit!), What examples can you give for business applications (or really, any application having to deal with a relate-able problem) that would make it easier to digest the MSDN documentation on the subject?

+1  A: 

Other than GUI...

  1. event dispatching; some of my business apps are quite complicated, talk to hardware devices, and rely on event queues to keep everything in synch. Delegates are used by these apps for event dispatching.
  2. business rules; some of my business apps have a partial soft-coding ability, where certain events trigger certain rules that are kept in a database. Delegates (in a Dictionary) are used to execute the rules on the client-side. (Plug-ins could be supported, but current are not needed).
  3. general secondary threads (using the SafeThread class, of course!)
Steven A. Lowe
Point #2 interests me; do you have a code snippet that shows how that works?
George Stocker
@[Gortok]: the rule names the action and returns a datarow, the dictionary holds a delegate for the action method keyed by name; the action method takes a datarow
Steven A. Lowe
+1  A: 

Anytime when you execute any asynchronous operations, such as making webservice calls, you can use delegate so when the call returns, you can initiate the delegate call for the target to handle things.

Boon
+4  A: 

I think this question reflects the many ways to skin a cat. I find delegates (and lambdas) nearly as fundamental as a "for" loop.

Here's one context in which I used delegates recently (formatting and names changed for presentation purposes:)

protected T[] SortLines<T>(Func<T> createLine, IEnumerable<T> unsorted)
where T : LineType
{
    Func<IEnumerable<T>, IEnumerable<T>> sorter = (lines => lines);

    switch (settings.OrderSort)
    {
        case OrderSort.ByA: 
            sorter = (lines => lines.OrderBy(x => x.A)); break;
        case OrderSort.ByB:
            sorter = (lines => lines.OrderBy(x => x.B)); break;

        // and so on... a couple cases have several levels of ordering
    }

    bool requiresSplit = // a complicated condition
    if (requiresSplit)
    {
        var positives = unsorted.Where(x => x.Qty >= 0);
        var negatives = unsorted.Where(x => x.Qty <  0);

        return sorter(negatives).Concat(
               new T[] { createLine.Invoke() }).Concat(
               sorter(positives)).ToArray();
    }
    else
        return sorter(unsorted).ToArray();
}

So this sorts a group of items based on some criteria, and then it either returns the whole list sorted, or it breaks it in two, sorts both halves separately, and puts a separator in between them. Good luck doing this elegantly if you can't express the concept of "a way to sort something", which is what the delegate is for.

EDIT: I guess Concat and OrderBy are 3.0-specific, but this is still the basic idea.

mquander
lambdas are 3.0 specific as well.
Benjol
+1  A: 

To my knowledge, a .NET delegate is essentially an implementation of a single-method interface, without all the class declaration hoopla. I wish we had them in Java, personally. Think of a comparator class:

class MyComparator<Circle> extends Comparator<Circle> {
    public int compare(Circle a, Circle b) {
        return a.radius - b.radius;
    }
}

Anyplace this pattern is useful, a delegate could be useful instead.

I hope I'm right, but go ahead and vote me down if I'm wrong; it's been too long since I saw any C# :)

Kevin Conner
Upvoted just for the college try. That way you can't blame me if you're downvoted. :-D
George Stocker
You're too kind :)
Kevin Conner
+1  A: 

One common pattern I've seen over the years (in various languages) is to "freeze" the result of a decision to move logic out of a loop into a setup. In pseudo-code (because the technique varies with language):

some_condition = setup_logic
...
while (not terminated) {
    data = obtain_data
    if (some_condition)
        process_one (data)
    else
        process_two (data)
}

The point is that if some_condition doesn't change based on anything in the loop, then there's really no benefit from repeatedly testing it. Delegates/closures/etc. allow the above to be replaced by this:

some_condition = setup_logic
if (some_condition)
    selected_process = process_one
else
    selected_process = process_two
...
while (not terminated) {
    data = obtain_data
    selected_process (data)
}

(Of course, a Real Functional Programmer would have written the setup as:

selected_process = if (some_condition) process_one else process_two

;-)

This generalizes nicely to multiple alternatives (instead of just two). The key idea is to decide in advance what action to take at a future point (or points), and then remember the chosen action rather than the value on which the decision was based.

joel.neely
+1  A: 

Delegates become extremely powerful when you start looking at them as functional constructs

.Net 2.0 included support for anonymous delegates, which formed the kernel of some of the functional concepts which were expanded upon by Linq. The syntax for an anonymous delegate is a bit bulkier than what Lambda's offer, but a lot of the core functional patterns are there in 2.0.

In the List generic type you have the following items you can work with:

  1. ConvertAll() - Uses a delegate to convert all the members of the list into another type (T). This is basically an implementation of a Map Function
  2. Find() and FindAll, both take delegates, and will return you either a single item (in the case of Find()), or all items that cause the delegate passed in to evaluate to true. This provides a Filter function, and also the definition of a Predicate (a function which evaluates to a boolean)
  3. There is an implementation of a ForEach() method which takes a delegate. Allowing you to perform an arbitrary operation against each element in the list.

Appart from List specific items, when your using anonymous delegates context is handled correctly, so you can implement Closure like structures. Or, on a more practicle level do something like:

ILog logger = new Logger();
MyItemICareAbout.Changed += delegate(myItem) { logger.Log(myItem.CurrentValue); };

And it just works.

There is also the DynamicMethod stuff, which allows you to define bits of IL (using Reflection.Emit), and compile them as delegates. This gives you a nice alternative to pure reflection for things like Mapping layers, and data access code.

Delegates are really a construct that allows you to represent executable code as data. Once you get your head around what that means, there are a whole lot of things that can be done. The support for these constructs in 2.0 was rudimentary when compared to 3.5, but still there, and still quite powerful.

ckramer
+1  A: 

Delegates are often used for event dispatch, however that's only because they are convenient to do so. Delegates are useful for any kind of method invocation. They also have a number of additional features, such as the ability to invoke asynchronously.

The basic reason for a delegate though is to provide a Closure, or the ability to call a function along with it's state, which is usually an object instance.

Mystere Man
+1  A: 

Another great use of delegates is as state machines. If your program logic contains repeated if...then statements to control what state it is in, or if you're using complicated switch blocks, you can easily use them to replicate the State pattern.

enum State {
  Loading,
  Processing,
  Waiting,
  Invalid
}

delegate void StateFunc();

public class StateMachine  {
  StateFunc[] funcs;   // These would be initialized through a constructor or mutator
  State curState;

  public void SwitchState(State state)  {
    curState = state;
  }

  public void RunState()  {
    funcs[curState]();
  }
}

My 2.0 delegate syntax may be rusty, but that's a pretty simple example of a state dispatcher. Also remember that delegates in C# can execute more than one function, allowing you to have a state machine that executes arbitrarily many functions each RunState().

Ron Warholic