Click here to Skip to main content
11,709,033 members (59,822 online)
Click here to Skip to main content

Why I use explicit interface implementation as a default implementation technique

, 28 May 2012 CPOL 51.6K 91
Rate this:
Please Sign up or sign in to vote.
EIMIs turn to be very useful in refactoring. I will try to prove it here. If you are working with large code bases, as I often do, this article is worth reading.

Introduction

Implementing interfaces in C# is an everyday programmer task. Most interfaces are implemented using implicit technique without any doubt. Explicit implementation not only is unfamiliar, but is considered to be a some awkward solution to a very rare problem of implementing two interfaces with same members.

In this article I'm going to discuss, why, in my opinion, explicit interface implementation - EIMI - should be considered as the default implementation technique. And how using EIMIs keeps interfaces and their implementations in a coherent state.

Basics

For the beginning, let's recall what implicit and explicit interface implementation means.
Given an interface ILogger
interface ILogger
{
    void Trace(string format, params object[] args);
}
We usually implement it in the following way
class Logger : ILogger
{
    public void Trace(string format, params object[] args) { }
}
This is an implicit interface implementation.

The meaning of implicit here is - the compiler decides on its own that a public method Logger.Trace(...) will implement the corresponding ILogger.Trace(...) interface member.

Let's put the above explicitly

class Logger : ILogger
{
    void ILogger.Trace(string format, params object[] args) { }
}

This is an explicit interface implementation - EIMI

What MSDN tells us about the need of EIMI?

Given two interfaces with the same members
interface IControl
{
    void Paint()
}

interface ISurface
{
    void Paint()
}
We need a way to distinguish the same members if we are going to implement both of the interfaces in a single class
public class SampleClass : IControl, ISurface
{
    void IControl.Paint() { }
    void ISurface.Paint() { }
}

The Key Difference of Explicit Implementation

Explicitly implemented methods and properties are private and inaccessible even to the implementing class
interface ILogger
{
    void Trace(string format, params object[] args);
}

class Logger : ILogger
{
    void ILogger.Trace(string format, params object[] args) { }
}

void main()
{
    Logger log = new Logger();
    log.Trace("");    // Compilation error, Trace() is not accessible
}
Explicitly implemented methods can be accessed through interface only
void main()
{
    ILogger log = new Logger();
    log.Trace("");    // Accessing through interface is OK
}

The Glory of the Explicit Implementation

Refactoring

Let's implement some simple interface ICalculator.
Then, let's trace revisions of the interface as software is being developed.
interface ICalculator
{
    void Solve(int startPoint);
}

class BasicCalculator : ICalculator
{
    public void Solve(int startPoint) { }
}
Half a year later, obviously, the interface is enriched with an additional method
interface ICalculator
{
    void Solve(int startPoint);
    void Solve(int startPoint, int endPoint);
}
In this half a year other stuff was added to BasicCalculator, as well. And here is what we might get after implementing the additional Solve(int startPoint, int endPoint) method
class BasicCalculator : ICalculator
{
    public void Solve(int startPoint);
    
    // other very useful stuff
    
    public void Solve(int startPoint, int endPoint);
}
In another half a year a major refactoring takes place, and the first Solve(int startPoint) method is removed from the ICalculator interface.
interface ICalculator
{
    // calculation with start point only is not good enough, method is removed
    
    void Solve(int startPoint, int endPoint);
}
Now, I will ask a question: "Do you know many programmers there who bother to go over all implementations and check if a particular change in interface leaves ghost public functions?"
class BasicCalculator : ICalculator
{
    public void Solve(int startPoint);      // this one is left here forever
    
    // other very useful stuff
    
    public void Solve(int startPoint, int endPoint);
}
I doubt, that the answer is yes. So, the first version of Solve(int startPoint) method is left inside all implementations of ICalculator interface forever.

With explicit implementation this will not going to happen !

interface ICalculator
{
    void Solve(int startPoint, int endPoint);
}

class BasicCalculator : ICalculator
{
    void ICalculator.Solve(int startPoint);    // Compilation error!
                                               // ICalculator has no such a method!    
    
    void ICalculator.Solve(int startPoint, int endPoint);
}

EIMI forces the compiler to look all over the code and tells us that we no longer need to implement the Solve(int) method.

In my opinion this "feature" is a killer and is a "must-to-use" in any large code base with many maintainers, especially if some of them are less experienced.

Decoupling From a Specific Implementation

There are other benefits of EIMIs as well.

Consider the following code

interface ICalculator
{
    void Solve(int startPoint);
}

class BasicCalculator : ICalculator
{
    public void Solve(int startPoint);

    // unfortunately, methods like this one seem to appear by their self in any enterprise code base
    public void UseSinToSolveTheProblemIfStartPointIsZero(int startPoint);
}

void main()
{
    var calculator = new BasicCalculator();    

    // bad! dependency on a specific implementation
    calculator.Solve(123);
}

The var keyword is very convenient and commonly used. As a result, in the example above the calculator variable becomes an instance of the BasicCalculator class. This is obviously bad, since the code becomes coupled to a specific implementation of a general ICalculator interface.

Later an inexperienced maintainer, will be tempted to use the calculator.UseSinToSolveTheProblemIfStartPointIsZero() method.

With EIMI the main() above won't compile since Solve() method is not accessible within the BasicCalculator class. We are forced to use the explicit ICalculator declaration instead of just the var keyword

void main()
{
    ICalculator calculator = new BasicCalculator();    

    // good! decoupled from a specific implementation
    calculator.Solve(123);
}

Decoupling Public Interface From Implementation Details

And the last (for this article) benefit of EIMI.
Consider this code
interface ILogger
{
    string Name { set; }
}

class Logger : ILogger
{
    public string Name { get; set; }
    
    private void GenerateAutoName()
    {
        Name = "MySophisticatedLogger";
    }
}

Here a public property Name is used to implement a private implementation detail inside the GenerateAutoName() method.

Half a year later we will probably add a validation code for the Name property

class Logger : ILogger
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set 
        {
            if (String.IsNullOrEmpty(value))
                throw new BadArgumentException();
                
            _name = value;
        }
    }
}
We no longer use the auto-implemented property feature of C#. But what happens inside our private GenerateAutoName() method? The validation code is "injected" into the method as well.
private void GenerateAutoName()
{
    Name = "MySophisticatedLogger";
}

Do we need the validation code of external data inside internal implementation? I guess that the answer is no.

Avoiding use of own public methods in private implementation details is a good practice, IMHO.

interface ILogger
{
    string Name { set; }
}

class Logger : ILogger
{
    public string ILogger.Name { get; set; }
    
    private void GenerateAutoName()
    {
        Name = "MySophisticatedLogger";        // compilation error!
    }
}
EIMI forces us to add private field _name as soon as we are going to use it in a private implementation.

Conclusion

In my every day programming I implement interfaces. The explicit way of implementing is the default for me. I use an implicit implementation only when I can not avoid it. Each time I'm refactoring, I see the actual benefits of EIMIs.

Here is a nifty implementation of a template method design pattern using EIMI

interface ICalculator
{
    void Solve();
}

abstract class CalculatorBase : ICalculator
{
    protected abstract void CalculateSolution();
    
    void ICalculator.Solve()
    {
        CalculateSolution();
    }
}

I like the way the design is expressed here. The interface Solve() method delegates the implementation details to a protected virtual method overridden by descendants.

EIMI keeps code cleaner and more maintainable.

Farther Reading

What is EIMI? EIMIs are good EIMIs are bad

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Mamasha Knows
Chief Technology Officer Cpp2Mtl Integration Solutions
United States United States
My real name is Reuven Bass. My first article here was published under the Mamasha Knows pseudonym. It worked. So, I stay with Mamasha for a while. (If it works - do not touch it)

Programming became my life from thirteen. I love coding. I love beauty. I always try to combine coding and beauty.

RB

You may also be interested in...

Comments and Discussions

 
QuestionI have a different thought Pin
Shivprasad koirala12-Jun-15 3:47
mvpShivprasad koirala12-Jun-15 3:47 
AnswerRe: I have a different thought Pin
Reuven Bass15-Jun-15 22:31
memberReuven Bass15-Jun-15 22:31 
GeneralRe: I have a different thought Pin
Shivprasad koirala17-Jun-15 17:33
mvpShivprasad koirala17-Jun-15 17:33 
QuestionMy vote of Pin
Reuven Bass17-Feb-15 6:05
memberReuven Bass17-Feb-15 6:05 
GeneralYou are telling us to use Visual Basic instead of C# Pin
Tigerfink25-Sep-14 3:04
memberTigerfink25-Sep-14 3:04 
QuestionMy rating is 5 Pin
Goel Himanshu15-Aug-14 20:20
professionalGoel Himanshu15-Aug-14 20:20 
AnswerRe: My rating is 5 Pin
Reuven Bass20-Aug-14 23:49
memberReuven Bass20-Aug-14 23:49 
QuestionHere is another practical example: Pin
Dietmar Schoder2-Aug-14 10:26
professionalDietmar Schoder2-Aug-14 10:26 
QuestionExcellent, Very Informative, Just one point Pin
qdev767-Nov-13 11:58
memberqdev767-Nov-13 11:58 
GeneralMy vote of 5 Pin
Joachim_797172017-May-13 1:26
memberJoachim_797172017-May-13 1:26 
GeneralMy vote of 5 Pin
Akhil_Mittal3-Mar-13 20:38
memberAkhil_Mittal3-Mar-13 20:38 
GeneralMy vote of 5 Pin
S. M. Ahasan Habib3-Feb-13 6:02
memberS. M. Ahasan Habib3-Feb-13 6:02 
GeneralMy vote of 5 Pin
Ivaylo5ev16-Aug-12 0:44
memberIvaylo5ev16-Aug-12 0:44 
GeneralMy vote of 5 Pin
Ravi Lodhiya13-Jun-12 3:58
memberRavi Lodhiya13-Jun-12 3:58 
GeneralRe: My vote of 5 Pin
Reuven Bass16-Jun-12 9:24
memberReuven Bass16-Jun-12 9:24 
QuestionThanks for an interesting read Pin
TeaTime12-Jun-12 22:48
memberTeaTime12-Jun-12 22:48 
AnswerRe: Thanks for an interesting read Pin
Reuven Bass16-Jun-12 9:22
memberReuven Bass16-Jun-12 9:22 
GeneralMy vote of 5 Pin
umlcat8-Jun-12 3:59
memberumlcat8-Jun-12 3:59 
GeneralRe: My vote of 5 Pin
Reuven Bass16-Jun-12 8:45
memberReuven Bass16-Jun-12 8:45 
GeneralMy vote of 5 Pin
Oshtri Deka7-Jun-12 5:24
memberOshtri Deka7-Jun-12 5:24 
GeneralRe: My vote of 5 Pin
Reuven Bass16-Jun-12 8:44
memberReuven Bass16-Jun-12 8:44 
GeneralMy vote of 5 Pin
shenba20095-Jun-12 14:36
membershenba20095-Jun-12 14:36 
GeneralRe: My vote of 5 Pin
Reuven Bass16-Jun-12 8:44
memberReuven Bass16-Jun-12 8:44 
GeneralMy vote of 5 Pin
Himanshu Thawait5-Jun-12 8:28
memberHimanshu Thawait5-Jun-12 8:28 
GeneralRe: My vote of 5 Pin
Reuven Bass16-Jun-12 8:43
memberReuven Bass16-Jun-12 8:43 
GeneralMy vote of 5 Pin
Paul @ The Computer Station5-Jun-12 1:54
groupPaul @ The Computer Station5-Jun-12 1:54 
GeneralRe: My vote of 5 Pin
Reuven Bass16-Jun-12 8:43
memberReuven Bass16-Jun-12 8:43 
QuestionThe issue with implementing explicitely Pin
Pascal Ganaye4-Jun-12 10:51
memberPascal Ganaye4-Jun-12 10:51 
AnswerRe: The issue with implementing explicitely Pin
Reuven Bass4-Jun-12 21:35
memberReuven Bass4-Jun-12 21:35 
GeneralRe: The issue with implementing explicitely Pin
Pascal Ganaye5-Jun-12 1:13
memberPascal Ganaye5-Jun-12 1:13 
GeneralRe: The issue with implementing explicitely Pin
Reuven Bass5-Jun-12 6:56
memberReuven Bass5-Jun-12 6:56 
GeneralRe: The issue with implementing explicitely Pin
qdev767-Nov-13 12:12
memberqdev767-Nov-13 12:12 
QuestionRe: The issue with implementing explicitely Pin
qdev768-Nov-13 9:03
memberqdev768-Nov-13 9:03 
AnswerRe: The issue with implementing explicitely Pin
Reuven Bass9-Nov-13 11:47
memberReuven Bass9-Nov-13 11:47 
GeneralMy vote of 5 Pin
Akram El Assas3-Jun-12 1:27
memberAkram El Assas3-Jun-12 1:27 
GeneralRe: My vote of 5 Pin
Reuven Bass16-Jun-12 8:42
memberReuven Bass16-Jun-12 8:42 
GeneralMy vote of 5 Pin
Barry Lapthorn2-Jun-12 9:05
protectorBarry Lapthorn2-Jun-12 9:05 
GeneralRe: My vote of 5 Pin
Reuven Bass16-Jun-12 8:42
memberReuven Bass16-Jun-12 8:42 
GeneralGreat article on not-so-familiar topic Pin
StevePro Studios2-Jun-12 7:59
memberStevePro Studios2-Jun-12 7:59 
GeneralRe: Great article on not-so-familiar topic Pin
Reuven Bass16-Jun-12 8:41
memberReuven Bass16-Jun-12 8:41 
GeneralMy vote of 5 Pin
johannesnestler30-May-12 22:14
memberjohannesnestler30-May-12 22:14 
GeneralRe: My vote of 5 Pin
Reuven Bass31-May-12 2:44
memberReuven Bass31-May-12 2:44 
GeneralMy vote of 5 Pin
feeza.ibrahim30-May-12 21:33
memberfeeza.ibrahim30-May-12 21:33 
GeneralMy vote of 5 Pin
P.Salini29-May-12 0:58
memberP.Salini29-May-12 0:58 
QuestionVB.Net Pin
Pascal Ganaye28-May-12 21:50
memberPascal Ganaye28-May-12 21:50 
AnswerRe: VB.Net Pin
Reuven Bass3-Jun-12 4:44
memberReuven Bass3-Jun-12 4:44 
GeneralMy vote of 5 Pin
Madhan Mohan Reddy28-May-12 18:14
memberMadhan Mohan Reddy28-May-12 18:14 
GeneralRe: My vote of 5 Pin
Reuven Bass28-May-12 22:25
memberReuven Bass28-May-12 22:25 
GeneralWell thought out Pin
Stephen Inglish28-May-12 18:00
memberStephen Inglish28-May-12 18:00 
GeneralRe: Well thought out Pin
Reuven Bass28-May-12 20:34
memberReuven Bass28-May-12 20:34 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150819.1 | Last Updated 28 May 2012
Article Copyright 2012 by Mamasha Knows
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid