What is the point of an explicit C#interface implementation?

Asked

Viewed 551 times

10

I usually use interfaces in PHP and I was able to do a similar example, only for tests, in C#.

class MyClass : IWriter {
    public string Writer(string str) {
       return str;
    }
}

interface IWriter{
       public string Writer();
}

However, I was advised that this implementation above is called "implicit" and that in some cases it was recommended to use the "explicit implementation".

I took a look at the link Explicit interface implementation (C Programming Guide#), but it caused confusion. Because I can’t see yet any case where I would need to use the "explicit implementation".

Of course as I’m used to PHP may be the reason for the confusion, but it’s the first time I see an explicit implementation of interface in a language.

In the MSDN example, it looks like this:

class Test 
{
    static void Main()
    {
        SampleClass sc = new SampleClass();
        IControl ctrl = (IControl)sc;
        ISurface srfc = (ISurface)sc;

        // The following lines all call the same method.
        sc.Paint();
        ctrl.Paint();
        srfc.Paint();
    }
}


interface IControl
{
    void Paint();
}
interface ISurface
{
    void Paint();
}
class SampleClass : IControl, ISurface
{
    // Both ISurface.Paint and IControl.Paint call this method. 
    public void Paint()
    {
        Console.WriteLine("Paint method in SampleClass");
    }
}

What is the advantage of using explicit interface implementation over implicit?

When should I use implicit implementation and when, explicit?

2 answers

13

This has to do with object scope isolation. At the beginning of the example you mentioned, we can see that two objects are created, each with a different view of the object:

IControl ctrl = (IControl)sc;
ISurface srfc = (ISurface)sc;

Which translates as follows::

Create a variable Ctrl, to introduce me to the object sc as a Icontrol.
Create a variable srfc, to introduce me to the object sc as a Isurface.

However, when calling the method Paint() of ctrl what you see is not specific presentation of the interface IControl, but the generic content generated by the implementation of the class. The same applies to ISurface.

You may then be hurting the return expectations in other parts of your code.

  • As in C# we have the question of being able to have two methods with the same name, for me makes sense the explicit implementation. In languages like PHP, which does not accept methods with equal names for example, it would make no sense at all.,

  • 4

    @Wallacemaxters one thing has nothing to do with the other. Overloding is unrelated to this. It is even possible for the interface to have more than one full me with the same name (but not the same signature). In fact it is opposite. In PHP it would make even more sense. This mechanism is to disambiguate the implementation of the same method (same signature). Note that technically the name is different, since it has a "surname" in it.

10


In fact, the recommended is the implicit one. There are cases where explicit is necessary. There are controversies whether this is a good thing or not. Some say it shouldn’t even exist in language because it can create confusion. I am always of the opinion that if there is something that can solve a problem better, you should give it that option, even if you have restrictions of use. Misuse is a problem that any resource may have.

Explicit X implicit interface

The implicit is what everyone does all the time, you implement in the class one or more methods that a "command" interface and that this class wants to conform. It’s no secret.

The explicit is the implementation nominally telling which interface this implementation should be used for. It is an exceptional form of implementation because there will be some situation where a behavior different from the normal class is required when waiting for the interface.

Remembering what polymorphism is

In polymorphism you can treat an object of one type as if it were of another type. So if you create a method that takes, for example, a IEnumerable, any object that implements this interface, can be passed to that method and all it will do is access the GetEnumerator() (specified by the interface). It will not access other parts of the object, so it does not matter to it the rest it has on the object. All that matters is that it’s there.

The C# compiler ensures the presence of what matters. In most cases the presence of the method in so-called implicit form is sufficient and everything will work.

What good is?

As much as the ideal is to do it one way, there are always situations where things don’t work out the way you want. In addition there is language limitation in making certain patterns that the solution turns out to be the use of the explicit interface. Here are the main reasons to use.

Diamond problem

There are some rare cases where this implementation should be a little different. This occurs more often when there are conflicting implementations of two interfaces. One must work one way and the other must work another way. Normally you could only have the implementation one way. The explanation of the implementation allows for a variation. A common situation occurs in the case of diamond problem. The interface helps solve the problem, but there are cases that can become a bigger problem having the same implementation for more than one interface.

To make explicit the interface name is used before the method name. Example:

public void Paint() { //implícita
    WriteLine("Paint method in SampleClass");
}
void IControl.Paint() { //explícita para a IControl
    WriteLine("IControl.Paint");
}
void ISurface.Paint() { //explícita para a ISurface
    WriteLine("ISurface.Paint");
}

How it performs:

var sc = new SampleClass();
IControl ctrl = (IControl)sc;
ISurface srfc = (ISurface)sc;

sc.Paint(); //Paint method in SampleClass
ctrl.Paint(); //IControl.Paint
srfc.Paint(); //ISurface.Paint

See the effects of calling by class and by each of the interfaces. Note how each call executes a different method even though it is theoretically the same method. It is working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

Specialization

Another case is that the class implementation can be done more efficiently or do something extra, but this may not conform to what is expected in the interface. So when it is used in a place that is expected to interface, it runs the simplest and most compatible implementation. When you can call the class implementation call the implementation "improved". This improved version could hurt the expectation of what the interface should do.

Compatibility

It can be useful in case of future interface changes, so it will help maintain compatibility with the old and new version, after all the interface now requires something that already existed in its class. This is common in more internal systems, especially when adding a method with an existing name but with a new signature.

An example would be an interface ICalculo who has a method CalculaSaldo(), a new method is created CalculaSaldo(TipoCalculo tipo). Only that the class that already conformed to this interface had already anticipated this need and created a method with this signature, but the implementation does not match what is expected of this method specified in the interface. The solution is to create a new method explicitly to meet the interface.

That is, it is Gambi, it should never be done this, but there are cases of need and when it happens at least it is a solution.

Encapsulation

It can help improve encapsulation, so you make it clear that implementations are different, even if they are not. In doing so, at least when you need it, you can change one of them without worrying about what will happen to the publicly exposed method. Example:

interface IDisposable {
    void Dispose();
}
class MyFile : IDisposable {
    void IDisposable.Dispose() {
        Close();
    }
    public void Close() {
        // fecha o que tem que fechar aqui
        SuppressFinalize(this);
    }
}
Public static void Main() {
    var file = new MyFile();
    file.Dispose(); //erro não pode chamar aqui
    IDisposable file2 = new MyFile();
    File2.Dispose(); //ok, funciona
}

Thus the call of the method Dispose() is prevented when called by the class. Which is a good thing, since many programmers make this call by mistake, which is not recommended and they don’t know it.

It is a way to simulate a private implementation of the interface. There are cases where the concrete implementation does not need the interface methods for it itself. It needs only to meet the demand of the interface, so it is better to hide it from the concrete objects generated based on it.

This is a form of explicitly program for the interface and not for implementation.

The best way is always to meet the ISP, and explicit implementation can facilitate or hinder this. Here it depends on the case, not always what we have in hand can be the ideal.

Classes that inherit from their class with explicit implementations do not receive these implementations. Neither can they have them virtual. Only implicit ones are inherited. This is an important thing to observe when thinking about design hierarchy. There are cases where you want this and want to maintain the right level of specialization.

One advantage of using this technique is that if one day the interface removes a method from your contract (rarely happens), the explicit interfaces will generate an error in the compiler and force you to remove them from the code. In the implicit implementation there is no error because it becomes part of the class. In fact, in that case the removal could only be done with great care and risk acceptance.

Can be bad

Besides being able to cause confusion in its use, not everyone understands what will be called and the person may have difficulties even to debug the code.

There is a practical problem of performance loss by being required to do Boxing in types by value, it is recommended to avoid explicit interfaces in these types. Cannot access a type per value from the interface without boxing it in a reference.

Completion

Like everything, it has advantages and disadvantages. Apart from the limitation of language, a good design avoid the use of this mechanism. And it should be avoided even

Eric Lippert’s article on the subject. Part 2.

Guideline by Brad Adams.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.