Indeed, objects should be manipulated solely in terms of their interface, not in terms of their concrete types.
internal
, which is good for encapsulationIn C#, a class can implement an interface either implicitly or explicitly:
interface ISomeService
{
public void DoSomething();
}
internal class ImplicitImplementation : ISomeService
{
public void DoSomething() { }
}
internal class ExplicitImplementation : ISomeService
{
void ISomeService.DoSomething() { }
}
For Microsoft C# Progamming Guide, Explicit Interface Method Implementation (EIMI) is only useful when a class implements two interfaces containing members with the same name and signature.
But that’s only half of the story: Explicit Implementation provides way more benefits.
Fact is: Explicit Implementation and Depencency Injection are a match made in heaven.
Code using Dependency Injection and interfaces works fine, regardless if the injected services are implemented explicitly or impicitly:
class Client
{
readonly ISomeService _service;
internal Client(ISomeService service)
{
_service = service;
}
internal void SomeMethod()
{
_service.DoSomething();
}
}
Here, rightly, service
is injected in terms of ISomeService
and Client
would never know the corresponding concrete class. And, indeed, it needn’t know: it is the core of the Dependency Inversion Principle.
We implement interfaces exactly because we want to separate the contract from the implementation, and decouple the clients from implementation.
We don’t inject service
as its concrete class, because it would just create unnecessary and noxious coupling.
That’s the key: implementing the interface explicitly forces all the clients to use the interface. Who wants to use the concrete class, will have to downcast.
Isn’t it a limitation? No: it is in fact a feature. Because you will never need to downcast.
If you find yourself casting down to an implementation, you are doing it wrong.
Interfaces are created in the first place to promote Programming To An Interface and discouraging Programming To An Implementation.
The idea behind Programming To An Interface is to base the programming logic on the contract, rather than on the internal implementation details. Programming To The Interface makes code more reusable.
There are two benefits to manipulating objects solely in terms of the interface defined by abstract classes:
- Clients remain unaware of the specific types of objects they use, as long as the objects adhere to the interface that clients expect.
- Clients remain unaware of the classes that implement these objects. Clients only know about the abstract class(es) defining the interface. This so greatly reduces implementation dependencies between subsystems that it leads to the following principle of reusable object-oriented design:
- Program to an interface, not an implementation.
Don’t declare variables to be instances of particular concrete classes. Instead, commit only to an interface defined by an abstract class
Design Pattern: Elements of Reusable Object-Oriented Software
What if you need to declare variables of particular concrete classes?
I challenge that this is even needed. In fact, I can’t think of a single case for an instance, passed down to a method or to a class constructor in terms of an interface, to be cast down to the concrete type.
In other words, there is no single reason to have Implicit Implementation on dependencies and parameters.
Explicit Implementation is just as a way to enforce that, and to prevent the consumption of concrete classes. As such, it is a best design practice, as it enforces the Dependency Inversion Principle.
If there’s an interface, why ever circumventing it?
TL;DR
Prefer testing to the interface over testing on the implementation.
Tests too should only deal with explicitly implemented method: they should exercise the public interface anyway, as they are meant to test the behaviour of a class just like it is consumed by its clients.
You don’t test private methods for the same reason: private methods are an implementation detail that could change during the refactor cycle, they are private for hiding the implementation, and you don’t want to test implementation details.
Private methods and methods not part of any interface are alike, and the same rational applies: tests should always exercise a System Under Test in terms of its interface, rather than of its implementation. Explicit Implementation would just enforce this.
public class ExplicitClassTest
{
readonly ISomeService _sut; // System Under Test is defined in terms of its contract
public ExplicitClassTest()
{
_sut = new ExplicitImplementation();
}
void test_some_functionality()
{
_sut.DoSomething(); // this consumes the interface, so the behavior, rather than the implementation
...
}
}
On the contrary, Implicit Implementation comes with some drawbacks: it pollutes the code with unneeded public
modifiers.
To promote encapsulation, a class should use the lowest access modifier needed. There’s no use of having a public class with public methods, if the class is not meant to be exposed to other projects.
Unfortunately, implicitly implemented methods need to be public
.
The following code won’t compile:
interface ISomeService
{
internal void Foo();
}
class SomeService : ISomeService
{
internal void Foo() {} // this needs to be public.
}
Foo()
needs to be public
regardless of how it was designed to be consumed. That’s unfortunate.
Even worse, marking it as public
in the class is not enough: the compiler would complain that also the upstream method in ISomeService
needs to be made public
. So, the problem would propagate up to the whole interface.
interface ISomeService
{
public void Foo();
}
class SomeService : ISomeService
{
public void Foo() {}
}
This does not happen with Explicit Implementation.
The following code would happily compile:
interface ISomeService
{
internal void Foo();
}
class SomeService : ISomeService
{
void ISomeService.Foo() { }
}
Just add the following to the project .csproj
file:
<ItemGroup>
<InternalsVisibleTo Include="YourTestProject" />
</ItemGroup>
If you stick to the convention of having test project names ending with .Test
, you can also use:
<ItemGroup>
<InternalsVisibleTo Include="$(MSBuildProjectName).Test" />
</ItemGroup>
TL;DR
Explicit Implementation promotes maintenaibility
When a method is removed from an interface (e.g. it’s moved to another interface during a refactoring), explicit implementation would force the compiler to look all over the code and identify all the places where the method is no longer needed. With Implicit Implementation, a class might end up having am unused, ghost public function.
For example:
internal interface ISomeService
{
public void MethodOne();
public void MethodTwo();
}
internal class ImplicitImplementation : ISomeService
{
public void MethodOne() { }
public void MethodTwo() { }
}
internal class ExplicitImplementation : ISomeService
{
void ISomeService.MethodOne() { }
void ISomeService.MethodTwo() { }
}
If the MethodTwo()
is removed from the interface:
internal interface ISomeService
{
// void MethodTwo(); // removed
}
internal class ImplicitImplementation : ISomeService
{
public void MethodOne() { }
public void MethodTwo() { } // <- Ghost Public Function
}
internal class ExplicitImplementation : ISomeService
{
void ISomeService.MethodOne() { }
void ISomeService.MethodTwo() { } // <- This won't compile
}
F# only supports Explicit Implementation.
That’s one of the justifications:
A well designed object-oriented program will have a strong focus on behavior rather than data, so it will use a lot of polymorphism, either using “duck-typing” or explicit interfaces, and will try to avoid having explicit knowledge of the actual concrete classes being passed around. What are types for? in F# For Fun and Profit
Seems like the same argument I just described.