Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid repeating the defaults of an interface

Tags:

c#

I have an interface with default parameters and I want to call the implementing method from within the implementing class (in addition to from outside it). I also want to use its default parameters.

However, if I just call the method by name I cannot use the default parameters because they are only defined in the interface.I could repeat the default specifications in the implementing method but that is not likely due to DRY and all that details(especially the fact that the compiler would not check that they actually match up with the interface's defaults!)

I solve this by introducing a member called _this that is the same as this except it is declared as the interface type. Then when I want to use default parameters, I call the method with _this. Here is sample code:

public interface IMovable
{
    // I define the default parameters in only one place
    void Move(int direction = 90, int speed = 100);
}

public class Ball: IMovable
{
    // Here is my pattern
    private readonly IMovable _this;

    public Ball()
    {
        // Here is my pattern
        _this = this;
    }

    // I don't want to repeat the defaults from the interface here, e.g.
    // public void Move(int direction = 90, int speed = 100)
    public void Move(int direction, int speed)
    {
        // ...
    }

    public void Play()
    {
        // ...

        //This would not compile
        //Move();

        // Now I can call "Move" using its defaults
        _this.Move();

        // ...
    }
}

Is there anything wrong with this pattern or a way to solve the problem in a better way? (Incidentally, I think this is a flaw in the language that I have to do something like this)

EDIT: Not a dup of Why are C# 4 optional parameters defined on interface not enforced on implementing class? ... I am primarily asking how to work around this language quirk, not asking why it was designed that way

like image 653
JoelFan Avatar asked May 10 '16 22:05

JoelFan


People also ask

What are default interface methods?

Default interface methods enable an API author to add methods to an interface in future versions without breaking source or binary compatibility with existing implementations of that interface. The feature enables C# to interoperate with APIs targeting Android (Java) and iOS (Swift), which support similar features.

Are Interfaces public by default?

The Interface Body Default methods are defined with the default modifier, and static methods with the static keyword. All abstract, default, and static methods in an interface are implicitly public , so you can omit the public modifier. In addition, an interface can contain constant declarations.

Should I always create an interface for every class?

In most cases, a final class is the best thing you can create. If a user doesn't like your class, they can simply choose not to use it. However, if you're building up a hierarchy of objects you should introduce an interface for every class.

How do you override an interface in C#?

Read( ) is then overridden in a Note type that derives from Document . using System; interface IStorable { void Read( ); void Write( ); } // Simplify Document to implement only IStorable public class Document : IStorable { // the document constructor public Document(string s) { Console.


2 Answers

You have three options.

Use an Extension Method as a Default

public interface IMovable
{
    void Move(int direction, int speed);
}

public static MovableExtensions
{
    public static void Move(this IMovable movable)
    {
        movable.Move(90, 100);
    }
}

Explicitly Implement the Interface

This way you do not have to repeat the defaults defined in the IMovable interface, and the defaults for the interface and implementation can never go out of sync.

public class Ball : IMovable
{    
    void IMovable.Move(int direction, int speed)
    {
    }
}

Repeat the Default Arguments

public class Ball : IMovable
{    
    public void Move(int direction = 90, int speed = 100)
    {
    }
}

There could be two users of your code: one who uses only the IMovable interface, and one who uses only the Ball class. Arguably there could be an obscure scenario in which the defaults for moving an IMovable should be different than the defaults for moving a Ball, and neither user should have to care about the defaults they aren't looking at.

I concede this explanation is not very satisfying. If you want more info on why the language was designed this way, read the question and top answer Giorgi Nakeuri linked to in his comment on your question: Why are C# 4 optional parameters defined on interface not enforced on implementing class?

like image 141
Timothy Shields Avatar answered Oct 05 '22 07:10

Timothy Shields


Then use explicit implementation, when you cast and call it as the interface you will get the interface defaults, when you call it with the class you will get the class defaults eg:

public class Ball : IMovable
{
    //this uses the interface defaults
    //notice how you dont need to define the default values again
    //they are only specified once, in the interface definition
    void IMovable.Move(int direction, int speed)
    {
        Debug.WriteLine(direction + "," + speed);
    }

    //now for the specific case of this class you can have your own defaults
    //or none, just what ever fits your needs
    public void Move(int direction = 20, int speed = 10)
    {
        Debug.WriteLine(direction + ","+ speed);
    }

    public void Play()
    {
        Debug.WriteLine("From interface");
        ((IMovable) this).Move();
        Debug.WriteLine("From this class defaults");
        Move();
    }
}

And the output

From Interface
90, 100
From this class defaults
20, 10

like image 33
bto.rdz Avatar answered Oct 05 '22 07:10

bto.rdz