MrKatSwordfish
MrKatSwordfish

Reputation: 1524

Passing anonymous/lambda functions to void delegates with no parameters? [C#]

I've been exploring C# delegates and anonymous/lambda functions, and I have some questions about how they interact. From what I understand, a simple delegate object can have predefined return and parameter types, and any named function with those same return/parameter types can be assigned to the delegate.

In my case, however, I've been working on a game where the Player can enqueue multiple Commands into their commandList. At some point after being added to the command list, commands are eventually executed by the player..

I started implementing this by creating specific subclasses for each command (AttackCommand, HealCommand, etc.), but then later found that to be tedious when it came to prototyping a variety of new commands. I thought it would be cool, for testing purposes, to create a CustomCommand class with a member delegate so that I could define and pass functions anonymously and quickly iterate on new game design ideas.

public class CustomCommand : Command {

    public delegate void CommandDelegate();
    private CommandDelegate func;

    public CustomCommand( CommandDelegate del ){
        func = del;
    }

    public Execute(){
        func();
    }
}

Then Player has a method that defines an anonymous function and uses it to construct a CustomCommand. However, something that confuses me a little bit is the fact that the arguments of this method seem to be able to be stored in the CustomCommand's delegate:

//inside Player class..
//command to steal gold from a target!
public CreateCustomCommand( Player targetPlayer ){
    CustomCommand.CommandDelegate anonCommand = delegate()
    {
         //Steals up to amount passed..
         int goldToSteal = targetPlayer.StealGold(25);
         gold += goldToSteal;
    };

    CustomCommand newCommand = new CustomCommand( anonCommand );
    commandList.Enqueue( newCommand );
}

//Command is automatically executed later..

I've tried this code, and not only does it compile, but it also works; money is stolen from the target and added to the source player. I'm happy that it works, but it's a little bit unsettling that I'm not sure what exactly is going on behind the scenes..

Here's what I'm having a hard time understanding:

Inside the CreateCustomCommand method (of Player), gold is in scope as it is a member of the Player class, and targetPlayer is in scope because it's a parameter.. But how is it that these things can be wrapped up in a anonymous function and passed to a void, parameterless delegate that's inside another object and still work? What's happening here? Does the creation of an anonymous function store references to all of the objects that it contains?

This seems extremely flexible compared to assigning named functions to delegates with matching return/parameter types, but are there any major drawbacks or pitfalls? Also, is this technique related to (or part of) any particular design pattern or programming methodology?

Upvotes: 1

Views: 740

Answers (1)

MrKatSwordfish
MrKatSwordfish

Reputation: 1524

If I understand this correctly, this works because anonymous functions make use of closures. Closures are blocks of code that can capture (See: Variable Scope In Lambda Expressions) the variable environments in which they were made.

So, because the CreateCustomCommand method defined an anonymous function (a closure), the anonymous function captured and maintained access to the variables that were in scope of CreateCustomCommand.

Thanks to @HansPassant for pointing me in the right direction!

Upvotes: 1

Related Questions