Karl Seguin

Sponsors

The Lounge

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Back to Basics: Delegates, Anonymous Methods and Lambda Expressions

Introduction

Like generics, delegates are one of those features that developers use without really understanding. Initially this wasn't really a problem since delegates were reserved for fairly specific purposes: implementing callbacks and as the building-block for events (amongst a few other edge cases). However, each version of .NET has seen delegates evolve, first with the introduction of anonymous methods in 2.0 and now with lambda expressions in C# 3.0. With each evolution, delegates have become less of an specific pattern and more of a general purpose tool. In fact, most libraries written specifically for .NET 3.5 are likely to make heavy use of lambda expressions. As always, our concern isn't just about understanding the code that we use, but also about enriching our own toolset. Seven years ago it wouldn't have been abnormal to see even a complex system make little (or no) us of delegates (except for using the events of built-in controls). Today, however, even the simplest systems heavily relies on them.

Delegates

The best way to learn about all three framework/language feature is to start from the original and build our way up, seeing what each evolution adds. Delegates have always been pretty simple to understand, but without any good reason to use them, people never really latched on to the concept. It's always easier to understand something when you can see what problem it solves and how it's used - and examples of delegates always seem contrived.

Delegates are .NETs version of function pointers - with added type safety. If you aren't familiar with C or C++ (or another lower level languages) that might not be very helpful. Essentially they let you pass a method into another method as an argument. Although many developers understand the concept in languages such as JavaScript, the strictness of C#/VB.NET makes it a little more confusion. For example, the following JavaScript code is completely valid (and even common):

function executor(functionToExecute)
{
   functionToExecute(9000);
}
var doSomething = function(count){alert("It's Over " + count);}
executor(doSomething);

Although simplistic, the above code shows how a function can be assigned to a variable (not the return value mind you, the actual function body) and then passed around as a parameter into a function. This parameter can then be executed as you would any other function.

The only difference in .NET is that you can't just assign any function to any variable and pass it into any method. Instead everything has to be properly typed. That's where delegates come in, they let you define the signature for a method – its parameters and return type. So, to build the above code in C#, we use the following:

public delegate void NotifyDelegate(int count);
public class Executor
{
   public static void Execute(NotifyDelegate notifier)
   {
       notifier(9000);
   }
}

public class Program
{
     public static void Main(string[] args)
     {
         NotifyDelegate notifier = Alert;
         Executor.Execute(notifier);
     }
     public static void Alert(int count)
     {
        Console.WriteLine("It's over {0}", count);
     }
}

It seems like a lot more code, but a good chunk of it is simply the requirement for everything in .NET to be in a class. The first, and most important, line is the definition for the delegate itself. Delegates are much like classes, interfaces, structures or enums – they define a type. Here we've defined a type named NotifyDelegate. Any method can be assigned to a variable of type NotifyDelegate provided that method has the same signature: it must return void and take a single parameter of type int. In the above code I explicitly assigned the Alert method to a variable named notifier for demonstration purposes only, the following would have been just as acceptable:

Executor.Execute(Alert);

The point is that a delegate can be used like any other type, the difference is simply that its assigned to a method. The other point to keep in mind is that my example used a static method (Alert). You can use either a static or an instance method – again, the only requirement is that it meets the defined method signature. Within an instance method you have access to all instance members just like any normal method (because it is a normal method).

Let's Get More Practical

So we have an idea of what delegates are, but when would we use them? As I mentioned earlier, in their normal form, their usage is fairly reserved for specific cases, most notably callbacks (if you've ever used an asynchronous method you likely had to supply a delegate to be called when the async call completed). However, lets look at a real example in which you might use a delegate. Initially this is going to be a little contrived, but as we move the example to anonymous methods and then lambda expressions, the example will feel more natural. This is a real example I use in my code.

Within our data layer we have a method that expects an array of objects and saves them all within a transaction. The method looks something like this (we use NHibernate, but the implementation details don't matter):

public class GenericStore<T>
{
    public void Save(params T[] entities)
    {
       using (var transaction = BeginTransaction())
       {
          try
          {
             foreach(T entity in entities)
             { 
                Save(entity);
             }
             transaction.Commit();
          }
          catch(Exception)
          {
             transaction.Rollback();
          }
       }
    }
}

We use this method, for example, when we want to switch the default group, something like:

public void SwitchDefault(Group newDefault)
{
   var oldDefault = GetDefaultGroup(); //implementation isn't important
   oldDefault.Default = false;
   newDefault.Default = true;
   DataFactory.For<Group>().Save(oldDefault, newDefault);
}

Of course, if our Save method throws an exception, we need to undo our code (rolling back the transaction undoes the database commit, but not the actual in-memory change we made). Here's one way to do that:

public void SwitchDefault(Group newDefault)
{
   var oldDefault = GetDefaultGroup(); //implementation isn't important
   oldDefault.Default = false;
   newDefault.Default = true;
   try
   {
      DataFactory.For<Group>().Save(oldDefault, newDefault);
   }
   catch
   {
      oldDefault.Default = true;
      newDefault.Default = false;
   }
}

This works fine, except we end up with a lot of try/catches all over the place. Instead we use a delegate (again, this is actually more code, but it's just a foundation to progress to anonymous methods). Here's our improved Save method:

public class GenericStore<T>
{
   public delegate void RollbackDelegate(T entities);

   public void Save(params T[] entities)
   {
      Save(null, entities);
   }
   public void Save(RollbackDelegate rollback, params T[] entities)
   {
      using (var transaction = BeginTransaction())
      {
         try
         {
            foreach(T entity in entities)
            { 
               Save(entity);
            }
            transaction.Commit();
         }
         catch(Exception)
         {
            transaction.Rollback();
            if (rollback != null)
            { 
               rollback(entities);
            }
         }
      }      
   }
}

The overloaded Save method is provided so that calling code can provide a delegate or not. We can use this code simply by doing:

public void SwitchDefault(Group newDefault)
{
   var oldDefault = GetDefaultGroup(); //implementation isn't important
   oldDefault.Default = false;
   newDefault.Default = true;
   DataFactory.For<Group>().Save(SwitchDefaultRollback, oldDefault, newDefault);
}

public void SwitchDefaultRollback(Group[] groups)
{
    groups[0].Default = false;
    groups[1].Default = true;
}

Whether or not you consider this an improvement over the try/catch solution is largely a matter of taste. I find neither particularly elegant. The problem with the delegate solution is the need for the extra method, and the awkward use of array indexes (we're relying on the Save method to pass the items back in the same order they were passed in).

Anonymous Methods

.NET 2.0 added a fairly significant improvement to delegates: anonymous methods. Delegates still exist and are still the ideal solution for a number of cases. However, for situations such as the one we're developing, they are far from perfect. What we want is a more concise way to create our callback as well as something that'll help us avoid the weird array indexing. Anonymous methods solve both those problem. We'll address each point separately.

Probably the most intimidating aspect of anonymous method is the way they are declared. Unlike normal methods, anonymous methods are declared within another method, using the delegate keyword:

public void SwitchDefault(Group newDefault)
{
   GenericStore<Group>.RollbackDelegate rollback = delegate(Group[] entities)
   {
      groups[0].Default = false;
      groups[1].Default = true;
   };	
   var oldDefault = GetDefaultGroup(); //implementation isn't important
   oldDefault.Default = false;
   newDefault.Default = true;
   DataFactory.For<Group>().Save(rollback, oldDefault, newDefault);
}

Like any nested-type, we access our delegate via its full name (GenericStore<Group>.RollbackDelegate). The delegate keyword creates an anonymous method – which behaves like any other method, except it isn't named and exists within a limited scope. Again, I assigned the anonymous method to a variable for demonstrative purposes, in real life you're more likely do to:

public void SwitchDefault(Group newDefault)
{
   var oldDefault = GetDefaultGroup(); //implementation isn't important
   oldDefault.Default = false;
   newDefault.Default = true;
   DataFactory.For<Group>().Save(delegate(Group[] entities)
     {
        groups[0].Default = false;
        groups[1].Default = true;
     }, oldDefault, newDefault);
}

The syntax is more confusing. If you look at it, you'll notice that we're really just passing 3 parameters to our Save method – our anonymous method, oldDefault and newDefault. The syntax will improve considerably when we look at the next evolution. For now, it's important that you understand the concept behind creating an anonymous method.

While the syntax might be the most confusing, the most important aspect of anonymous methods is their scope. Anonymous methods behave like any other code-block. In our above code that means that our anonymous method has access to oldDefault, newDefault and all the other instance members which might be defined (like the GetDefaultGroup method we're calling). That means that we can really simplify our code. First, we'll change our delegate so that it no longer passes back our array of entities:

public delegate void RollbackDelegate();

Along with the corresponding part of our Save method:

transaction.Rollback();
if (rollback != null)
{ 
   rollback();
}

Our calling code now looks like:

public void SwitchDefault(Group newDefault)
{
   var oldDefault = GetDefaultGroup(); //implementation isn't important
   oldDefault.Default = false;
   newDefault.Default = true;
   DataFactory.For<Group>().Save(delegate()
     {
        newDefault.Default = false;
        oldDefault.Default = true;
     }, oldDefault, newDefault);
}

I consider this much cleaner, not only because there's less chance of bugs, but also because the code is far more readable. All ambiguity around what groups[0] and groups[1] referred to has been removed.

Our solution still isn't perfect (the syntax around anonymous delegates is a little messy), but to me it's definitely a step in the right direction. We no longer have to create a full-blown method for each delegate, and having our scoped within the method gives us direct access to variables we'll likley need.

Lambda Expressions

While anonymous methods provide a new feature, lambda expressions merely provide an improved syntax. The improvement is rather significant though, which has made anonymous methods even more popular. At one point our delegate was passing along an array as a parameter:

public delegate void RollbackDelegate(T entities);

And, to be valid, our anonymous method had to be defined with the same signature:

delegate(Group[] entities){ ... }

Although we've moved beyond the need to pass-back the array, I want to look at lambdas from this point on, as it'll help make things clearer (and often times you'll have delegates with parameters). The lambda version of our above code is:

entities => {....}

Essentially, the => operator (some people call it the wang operator) replaces the need for both the delegate keyword as well as the parameter types. Additionally, if your delegate is a single statement, you can drop the brackets { }. If you have multiple parameters, you wrap them in parenthesis:

(entities, transaction) => {...}

If you don't have any parameters, like in our example, you use empty paranthesis:

() => {...}

It's easy to get mixed up with the syntax, but if you walk backwards through the code, hopefully everything makes sense. Here's what our implementation now looks like:

public void SwitchDefault(Group newDefault)
{
   var oldDefault = GetDefaultGroup(); //implementation isn't important
   oldDefault.Default = false;
   newDefault.Default = true;
   DataFactory.For<Group>().Save(() =>{newDefault.Default = false; oldDefault.Default = true;}, oldDefault, newDefault);
}

Some More Examples

To get a good feel for the syntax, let's look at some other, common, examples. We'll stick to the List<T> class, which exposes a number of methods which expect delegates.

To get the sum of all integers within a list using an anonymous method:

var ids = new List<int>{1,2,3,4,5};
var sum = 0;
ids.ForEach(delegate(int i){ sum += i;});

Using a lambda expression:

var ids = new List<int>{1,2,3,4,5};
var sum = 0;
ids.ForEach(i => sum += i);

To find a specific group by its id:

public Group FindGroup(int id)
{
   var groups = GetAllGroups(); //there might be a more efficient way!
   return groups.Find(delegate(Group g){return g.Id == id;});
}

Using a lambda expression:

public Group FindGroup(int id)
{
   var groups = GetAllGroups(); //there might be a more efficient way!
   return = groups.Find(g => g.Id == id);
}

Notice that using a lambda we don't even have to return true or false if a match is found. Lambdas explicitly returns the value.

Delegates and Generics

The last thing we'll cover is the synergy between delegates and generics. This is something I've covered in depth before, so we'll only briefly discuss it here. The .NET framework comes with a number of built-in delegates (for example, we might not need to define our own RollbackDelegate type as the .NET framework might already have one for the same method signature). It turns out that if you sprinkle some generic goodness of top of delegates, you can easily create a delegate for almost any situation. There are three core generic delegates within the .NET framework: Predicate, Func and Action. Each comes with a number of overloads to cover the most common cases:

delegate bool Predicate();
delegate bool Predicate<T1>(T1 parameter1);
delegate bool Predicate<T1, T2>(T1 parameter1, T2 paremter2);
delegate bool Predicate<T1, T2, T3>(T2 parameter1, T2 paremter2, T3 parameter3);

delegate T Func<T>(T returnType);
delegate T Func<T, T1>(T returnType, T1 parameter1);
delegate T Func<T, T1, T2>(T returnType, T1 parameter1, T2 paremter2);
delegate T Func<T T1, T2, T3>(T returnType, T1 parameter1, T2 paremter2, T3 parameter3);

delegate void Action();
delegate void Action<T1>(T1 parameter1);
delegate void Action<T1, T2>(T1 parameter1, T2 paremter2);
delegate void Action<T1, T2, T3>(T1 parameter1, T2 paremter2, T3 parameter3);

The difference between the three is the type of the return (Predicate always returns bool, Func returns T and Action returns void). The overloads just let us support multiple parameters.

Instead of using this delegate:

public delegate void RollbackDelegate(T entities);
...
public void Save(RollbackDelegate rollback, params T[] entities){...}

We could have simply used:

public void Save(Action<T[]> rollback, params T[] entities){...}

And instead of:

public delegate void RollbackDelegate();
...
public void Save(RollbackDelegate rollback, params T[] entities){...}

We could have simply used:

public void Save(Action rollback, params T[] entities){...}

Conclusion

Hopefully this helped clarify delegates, anonymous methods and lambdas, both in terms of their crazy syntax as well as how you can use them within your own code. When you combine this with a solid understanding of generics you end up with some powerful and concise code. You also end up with new ways to solve existing problems, which could otherwise be problematic and ugly. Don't be afraid to try using some of these solutions within your code. The best way to learn how pieces fit together and to actually try to make something work


Posted 11-27-2008 10:15 AM by karl
Filed under:

[Advertisement]

Comments

Matt Corr wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-27-2008 10:23 AM

Love your Back to Basics articles. Very easy to read and understand format.

Keep them coming :)

spacattac wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-27-2008 11:45 AM

Agreed!  I fall into the camp that's been using/inheriting these language features without necessarily a good grip on it and these BASICS have been great.

Joel Abrahamsson wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-27-2008 12:07 PM

Another great article! Please keep'em coming :)

Chris Tavares wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-27-2008 1:39 PM

Nice article. Are you planning to have another one that talks about closures and variable capture? That is a more advanced feature, granted, but it's incredibly powerful and you see it a lot in production code.

karl wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-27-2008 3:54 PM

Chris, not any time soon. But you did make me realize that I should provide an "Further Readings" section in my conclusion for people who want to read up more advanced details.

So, here are two links for anyone interested:

How anonymous methods are actually implemented:

blogs.msdn.com/.../686456.aspx

Understanding variable capture:

blogs.msdn.com/.../understanding-variable-capturing-in-c.aspx

Nate wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-27-2008 4:59 PM

Great article!

Was this in a response to the blank stares when you started talking about lamda expression during your Unit Test talk in Ottawa :-)

karl wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-27-2008 6:43 PM

@Nate:

Ya. It's actually good. A benefit of doing talks is you realize what all types of things about what people know or get and what they don't. Ends up giving talks is a great way to get material for blog posts :)

Leyu wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-28-2008 1:25 AM

Nice Article, one correction though

On the GenericStore<T> class which uses delegates

Delegate definition should be changed to  

public delegate void RollbackDelegate(params T[] entities);

It was defined as

public delegate void RollbackDelegate(T entities);

Reflective Perspective - Chris Alcock » The Morning Brew #233 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #233
on 11-28-2008 3:10 AM

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #233

DotNetKicks.com wrote Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-28-2008 8:37 AM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

karl wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-28-2008 9:38 AM

Good catch Leyu

Dew Drop - November 28, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - November 28, 2008 | Alvin Ashcraft's Morning Dew
on 11-28-2008 9:49 AM

Pingback from  Dew Drop - November 28, 2008 | Alvin Ashcraft's Morning Dew

Dew Drop - November 28, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - November 28, 2008 | Alvin Ashcraft's Morning Dew
on 11-28-2008 9:49 AM

Pingback from  Dew Drop - November 28, 2008 | Alvin Ashcraft's Morning Dew

Yoann. B wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-28-2008 12:06 PM

Great article

Very useful, thanks !

Richard wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-28-2008 2:18 PM

Super article! Give me more! ;)

What are you using to get that nice formating?

karl wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-28-2008 3:54 PM

@Richard:

CodeBetter uses

code.google.com/.../syntaxhighlighter

Bart Czernicki wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-30-2008 1:07 PM

Check out my article that goes over delegates from .net 1.x to 3.5 with code examples for download: silverlighthack.com/.../Evolution-of-delegate-syntax-from-NET-10-to-NET-35.aspx

Gerald wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 11-30-2008 5:01 PM

Hahahaha, it's over 9000!

I get it. Very funny.

brittlee wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 12-01-2008 5:08 AM

Its avery good article .Please Let such articles come up for better use in better way.

=====================================

Brettlee

<a href="http://www.widecircles.com ">http://www.widecircles.com </a>

Code Monkey Labs wrote Weekly Web Nuggets #40
on 12-01-2008 11:24 AM

Pick of the Week: Controlling Your Festive Lights with the .NET Micro Framework General New and Improved CLR 4 Thread Pool Engine : Daniel Moth writes about upcoming enhancements to the thread pool. xUnit.NET 1.1 Released : Brad Wilson announces a new

Alexander Shapovalov wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 12-02-2008 10:31 AM

Good article, but for people who don't know about NHibernate (like me) it's a little difficult to understand.

iherdyouliekmudkipz wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 12-04-2008 3:27 PM

TL;DR

My .NET Development Links | Dev102.com wrote My .NET Development Links | Dev102.com
on 12-05-2008 1:48 AM

Pingback from  My .NET Development Links | Dev102.com

Weekly Link Post 71 « Rhonda Tipton’s WebLog wrote Weekly Link Post 71 &laquo; Rhonda Tipton&#8217;s WebLog
on 12-07-2008 9:55 PM

Pingback from  Weekly Link Post 71 &laquo; Rhonda Tipton&#8217;s WebLog

Zayo wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 12-08-2008 4:44 AM

I'm a noob and this helped me a bit,

but still I don't get it wholly

But thx anyway, nice try :)

Scott wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 12-08-2008 2:18 PM

Thanks for this.  I now have a good grasp on lambdas...

Ramanujam wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 12-09-2008 9:58 AM

Thanks for this, Nice article

the jackol’s den » Delegates, Anonymous Methods and Lambda Expressions - Mikhail Esteves wrote the jackol&#8217;s den &raquo; Delegates, Anonymous Methods and Lambda Expressions - Mikhail Esteves
on 12-10-2008 7:32 AM

Pingback from  the jackol&#8217;s den    &raquo; Delegates, Anonymous Methods and Lambda Expressions - Mikhail Esteves

David wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 12-11-2008 12:40 PM

Great article!  Thanks.

joshka wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 12-18-2008 3:06 AM

The false and true are backwards for the code blocks where you've used an array instead of the objects. Appropriate perhaps given "I consider this much cleaner, not only because there's less chance of bugs, but also because the code is far more readable. All ambiguity around what groups[0] and groups[1] referred to has been removed." :D

Marcel Popescu wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 12-20-2008 5:44 PM

The Func<> delegates actually have T as the last argument (as in Func<T1, T2, T>) and also do not have it in the list of parameters, of course (so it's delegate T Func<T1, T2, T>(T1 parameter1, T2 parameter2);

dave wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 02-04-2009 9:49 PM

I totally don't understand your code.

You lost me at the delegates example.

I know what delegate are and how to use them, but I never do use them.

But I would like to use them one day.

Brian wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 02-19-2009 2:12 PM

With vague understanding of new C# 2.0 and 3.0 features, I came here searching for explanation of action delegate multiple parameters.  Left with a solid understanding of everything you presented.  That was a huge help!  

Especially liked the way you progressed from the familiar delegates to new territory.  Thanks!

Code Monkey Labs wrote Weekly Web Nuggets #40
on 02-22-2009 10:35 PM

Pick of the Week: Controlling Your Festive Lights with the .NET Micro Framework General New and Improved CLR 4 Thread Pool Engine : Daniel Moth writes about upcoming enhancements to the thread pool. xUnit.NET 1.1 Released : Brad Wilson announces a new

SoloTraveler wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 03-17-2009 9:35 PM

Nice article, but the code could be confusing

The Save method is recursively calling itself, with the first parameter inside the foreach and would result in stackoverflow

Cheers & Thanks

Jon Galloway wrote Troubleshooting an Intermittent .NET High CPU problem
on 04-09-2009 5:02 AM

We’d been getting sporadic reports of high CPU usage in Witty (a WPF Twitter client). I’d tried running

hadi teo wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 05-03-2009 10:21 AM

Hi,

According to the below code snippet, when exception occured, you will set the oldDefault.Default = true and newDefault.Default = false

  1. public void SwitchDefault(Group newDefault)  

  2. {  

  3.    var oldDefault = GetDefaultGroup(); //implementation isn't important  

  4.    oldDefault.Default = false;  

  5.    newDefault.Default = true;  

  6.    try  

  7.    {  

  8.       DataFactory.For<Group>().Save(oldDefault, newDefault);  

  9.    }  

 10.    catch  

 11.    {  

 12.       oldDefault.Default = true;  

 13.       newDefault.Default = false;  

 14.    }  

 15. }  

but based on this code snippet . groups[0].Default property is set to false and groups[1].Default property is set to true;

should it be :

groups[0].Default = true;

groups[1].Default = false;

  1. public void SwitchDefault(Group newDefault)  

  2. {  

  3.    var oldDefault = GetDefaultGroup(); //implementation isn't important  

  4.    oldDefault.Default = false;  

  5.    newDefault.Default = true;  

  6.    DataFactory.For<Group>().Save(SwitchDefaultRollback, oldDefault, newDefault);  

  7. }  

  8.  

  9. public void SwitchDefaultRollback(Group[] groups)  

 10. {  

 11.     groups[0].Default = false;  

 12.     groups[1].Default = true;  

 13. }  

Thanks for your clarification. I maybe wrong, please correct me

karl wrote re: Back to Basics: Delegates, Anonymous Methods and Lambda Expressions
on 05-03-2009 12:57 PM

@handi:

A few comments up, joshka pointed out the same thing. I have them reversed. My bad.  It does highlight the problem with using delegates (things are harder to follow) vs using anonymous methods.

Wimiro Technology Blog wrote Full Circle on Action<T>
on 06-12-2009 9:25 AM

Full Circle on Action

Add a Comment

(required)  
(optional)
(required)  
Remember Me?