BobSwanson
BobSwanson

Reputation: 423

Lambda implementing Interface

In the book I'm reading "Head First Design Patterns", Command Pattern there is an example where they're substituting an Interface with Lambda.

Is this something that only Java is capable of? Here is an example

From the book: enter image description here

// Receiver 
public class Light
{
    public void On() {
        Console.WriteLine("Lights on");
    }

    public void Off() {
        Console.WriteLine("Ligts off");
    }
}

// Command interface
public interface ICommand
{
    void Execute();
}

// Concrete command
public class SimpleCommandLightOn : ICommand
{
    private readonly Light light;

    public SimpleCommandLightOn(Light light) {
        this.light = light;
    }

    public void Execute() {
        light.On();
    }
}

// Concrete command
public class SimpleCommandLightOff : ICommand
{
    private readonly Light light;

    public SimpleCommandLightOff(Light light)
    {
        this.light = light;
    }

    public void Execute()
    {
        light.Off();
    }
}

// Invoker
public class SimpleRemoteControl
{
    private ICommand command;

    public void SetCommand(ICommand command) {
        this.command = command;
    }

    public void OnButtonPress() {
        command.Execute();
    }

    // OffCommand needs to be set
    public void OffButtonPress() {
        command.Execute();
    }
}

In the book they're stating that this is possible:

Light light = new Light();
remote.SetCommand(() => light.On());

However c# throws an error. Is this no the case when working with C#?

Upvotes: 6

Views: 4951

Answers (3)

Frank Schwieterman
Frank Schwieterman

Reputation: 24480

As an alternative, one can create an implementation of the interface that passes the calls through to lambda expressions.


public interface ICommand
{
    void Execute();
    int Calculate(int input);
}

public class LambdaCommand : ICommand
{
    readonly Action execute;
    readonly Func<int, int> calculate;

    public LambdaCommand(Action execute, Func<int, int> calculate)
    {
        this.execute = execute;
        this.calculate = calculate;
    }

    public void Execute() => execute();
    public int Calculate() => calculate();
}

...

remote.SetCommand(new LambdaCommand(() => light.On(), _ => _));

Upvotes: 0

Matthias
Matthias

Reputation: 1799

This does not work because in C#, lambda expressions map to delegates - a concept that does not exist in Java. Java has had a lot of these one-method interfaces for a long time before they finally introduced lambdas in Java 8. Given this and the lack of delegates, it was more or less natural to associate lambdas wit these one-method interfaces. C# / .NET, on the other hand, had delegates from the beginning and used them at many places where you would find a one-method interface in Java. Compare e.g. Observer and EventHandler.

So in a .NET API, you would consider using a delegate type like Action instead of ICommand, and then you would be able to use a lambda with it.

It should also be noted that .NET does have one-method interfaces, too. Some basic guidance about when to choose an interface or a delegate can be found at MSDN.

Upvotes: 7

Luaan
Luaan

Reputation: 63772

Matthias' answer is great, let me just add how a C# idiomatic way of declaring a command would look like:

delegate void Command();

That's it (though nowadays, you'd just use the generic Action delegate rather than defining your own). Your method would be

public void SetCommand(Command command)
{
  this.command = command;
}

and invoking the command is as simple as

command();

Calling the SetCommand method can look like this:

SetCommand(() => DoSomething()); // Lambda
SetCommand(delegate () { DoSomething(); }); // Anonymous method
SetCommand(Someone.DoSomething); // Named method - Someone can be a type or an instance

As you can see, there's little point in using an interface for something a simple delegate can do. Java uses the syntax it does because it never supported delegates, and because it supports anonymous interface implementations - something C# doesn't have.

As an added bonus, delegates natively support chains - so a delegate can represent a set of delegates that are to be executed in a sequence. This is mostly used in events - another syntax helper that makes your job a little bit easier, with the handy syntax of SomeEvent += someDelegate; to register an event handler.

Upvotes: 6

Related Questions