Interfaces in c Sharp dot net. ( Difference between Explicit and implicit use of interface methods)
An interface contains only the signatures of methods, properties, events or indexers. A class or struct that implements the interface must implement the members of the interface that are specified in the interface definition.An interface contains definitions for a group of related functionalities that a class or a struct can implement.
By using interfaces, you can, for example, include behavior from multiple sources in a class. That capability is important in C# because the language doesn't support multiple inheritance of classes. In addition, you must use an interface if you want to simulate inheritance for structs, because they can't actually inherit from another struct or class.
When a class or struct implements an interface, the class or struct must provide an implementation for all of the members that the interface defines. The interface itself provides no functionality that a class or struct can inherit in the way that it can inherit base class functionality. However, if a base class implements an interface, any class that's derived from the base class inherits that implementation.
You define an interface by using the interface keyword, as the following example shows.
Explicit Interface implementationusing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication10
{
class Program
{
static void Main(string[] args)
{
BMW D = new BMW();
Icar c = (Icar)D;
c.CarMadatory();
D.carOptional();
Console.Read();
}
}
//an interface expects only declarations
interface Icar
{
void CarMadatory();
}
class BMW : Icar
{
void Icar.CarMadatory()
{
Console.WriteLine("Engine, Tyre, Seat, Stering");
}
public void carOptional()
{
Console.WriteLine("CDPlayer");
}
}
}
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
}
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.
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 theSolve(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
ode
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 theBasicCalculator
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 theGenerateAutoName()
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!
}
}
Interfaces in c Sharp dot net. ( Difference between Explicit and implicit use of interface methods)
Reviewed by Share less to Learn More
on
6:31 PM
Rating:
No comments