You have probably implemented interfaces hundreds of times in C#, and
perhaps even created some of your own. But did you know that there are
actually two different ways to implement an interface in C#? There is
the common way - the way that almost everyone always uses, but then
there is a second way, called "Explicit Implementation". And no, it has
nothing to do with cursing or expletives (although, the first time I ran
across it, there might have been a few of those). Explicit
implementation is not used very often, but it is quite powerful - and
like all powerful things, can get you into trouble from time to time if
it isn't used carefully.
To kick things off, lets take a look at what Visual Studio has to say
about implementing an interface. Below is a screen shot of the Visual
Studio context menu about implementing an interface (in this case, the
IEnumerable interface):
If you choose "Implement interface 'IEnumerable'" you will get a block
of code in your class that looks like this:
public class MyEnumerable : IEnumerable
{
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
However, if you choose "Explicitly implement interface 'IEnumerable'",
you get the following:
public class MyEnumerable : IEnumerable
{
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
The difference is small but important - the addition of
IEnumerable.
in front of GetEnumerator
and the removal of public
. Essentially,
this is saying that the method GetEnumerator
is there specifically for
the interface IEnumerable
and no longer really for this class.
To understand what that means, let's take a look at a slightly more
complex example. Say that, for some reason, I have the following two
interfaces,
ITeacher
and IStudent
:public interface ITeacher
{
bool HasTenure { get; }
string Department { get; }
int CourseCount { get; }
}
public interface IStudent
{
int GraduationYear { get; }
string Major { get; }
int CourseCount { get; }
}
If you're sharp, you may have noticed that both have a property named
CourseCount
- and if you're sharper, you probably realized that while
they are named the same thing, they probably mean two different things.
In the context of a "Teacher", CourseCount
is the number of courses
that teacher is currently teaching. In the context of a "Student",
CourseCount
is the number of courses that the student is taking.
So what happens when a
StudentTeacher
comes along?! With the regular
old method of implementing interfaces, you would get something like
this:public class StudentTeacher : ITeacher, IStudent
{
private int _CoursesTeaching;
private int _CoursesTaking;
public StudentTeacher(int taking, int teaching)
{
_CoursesTeaching = teaching;
_CoursesTaking = taking;
}
//Of course a Student Teacher doesn't have tenure :P
public bool HasTenure
{ get { return false; } }
public string Department
{ get; set; }
public int GraduationYear
{ get; set; }
public string Major
{ get; set; }
public int CourseCount
{
get
{
//What do I do!!?
throw new NotImplementedException();
}
}
}
There is only one property called
CourseCount
, but there are two
distinct pieces of data that it represents. This is when we need
explicit interfaces. In this case, we want to explicitly implement the
CourseCount
property:public class StudentTeacher : ITeacher, IStudent
{
private int _CoursesTeaching;
private int _CoursesTaking;
public StudentTeacher(int taking, int teaching)
{
_CoursesTeaching = teaching;
_CoursesTaking = taking;
}
//Of course a Student Teacher doesn't have tenure :P
public bool HasTenure
{ get { return false; } }
public string Department
{ get; set; }
public int GraduationYear
{ get; set; }
public string Major
{ get; set; }
int ITeacher.CourseCount
{ get { return _CoursesTeaching; } }
int IStudent.CourseCount
{ get { return _CoursesTaking; } }
}
This means that when you call an instance of this class while in an
ITeacher
variable, you will get the value of _CoursesTeaching
- but
if you call it while it is stored in a
IStudent variable, you will get the value of _CoursesTaking
. For
instance, take a look at the following test code:class Program
{
static void Main(string[] args)
{
StudentTeacher st = new StudentTeacher(2, 3);
ITeacher teacher = st;
Console.WriteLine("Courses Teaching: " + teacher.CourseCount);
IStudent student = st;
Console.WriteLine("Courses Taking: " + student.CourseCount);
}
}
That code produces the following output:
Courses Teaching: 3
Courses Taking: 2
Another side effect of explicitly implementing an interface (or part of
one, as we are doing here), is that the explicitly implemented pieces
are not actually available off the class as regular calls - i.e., on the
class above, you couldn't ask an instance stored in a
StudentTeacher
variable what it's CourseCount
is. This is because it wouldn't know
what CourseCount
method to call. In fact, it doesn't even show up in
Visual Studio intellisense:
However, since the property is explicitly implemented, you can still
actually use it as a property name in the class. So we can give
StudentTeacher
a special CourseCount
property that is only available
when looking at the class as a StudentTeacher
:public class StudentTeacher : ITeacher, IStudent
{
private int _CoursesTeaching;
private int _CoursesTaking;
public StudentTeacher(int taking, int teaching)
{
_CoursesTeaching = teaching;
_CoursesTaking = taking;
}
//Of course a Student Teacher doesn't have tenure :P
public bool HasTenure
{ get { return false; } }
public string Department
{ get; set; }
public int GraduationYear
{ get; set; }
public string Major
{ get; set; }
int ITeacher.CourseCount
{ get { return _CoursesTeaching; } }
int IStudent.CourseCount
{ get { return _CoursesTaking; } }
public int CourseCount
{ get { return _CoursesTaking + _CoursesTeaching; } }
}
Now we can get the total number of courses as well:
class Program
{
static void Main(string[] args)
{
StudentTeacher st = new StudentTeacher(2, 3);
ITeacher teacher = st;
Console.WriteLine("Courses Teaching: " + teacher.CourseCount);
IStudent student = st;
Console.WriteLine("Courses Taking: " + student.CourseCount);
Console.WriteLine("Total Course Count: " + st.CourseCount);
}
}
Courses Teaching: 3
Courses Taking: 2
Total Course Count: 5
And there we go! That was your crash course in explicit interface
implementation in C#. You would have thought that at this point we
would have run out of C# language features to talk about here at SOTC,
but there always seems to be another one. As always, you can grab a zip
file containing all the code in this tutorial below.
Source Files:
Comments
Post a Comment