If we explicitly add the Interface to the child classes the program will run the same (at least as far as I can tell in my simple examples).
The program will not necessarily run the same; your examples are insufficient to illustrate the difference.
Would explicitly implementing the interface be a good or bad idea, or is it strictly a matter of preference?
It is a bad idea unless you intend to ensure interface re-implementation semantics.
Let me illustrate briefly. What does this program do?
using System;
interface IFoo { void Bar(); void Baz(); }
class Alpha : IFoo
{
void IFoo.Bar()
{
Console.WriteLine("Alpha.Bar");
}
void IFoo.Baz()
{
Console.WriteLine("Alpha.Baz");
}
}
class Bravo : Alpha
{
public void Baz()
{
Console.WriteLine("Bravo.Baz");
}
}
class CharlieOne : Bravo
{
public void Bar()
{
Console.WriteLine("CharlieOne.Bar");
}
}
class CharlieTwo : Bravo, IFoo
{
public void Bar()
{
Console.WriteLine("CharlieTwo.Bar");
}
}
class Program
{
static void Main()
{
IFoo foo = new Alpha();
foo.Bar();
foo.Baz();
foo = new Bravo();
foo.Bar();
foo.Baz();
foo = new CharlieOne();
foo.Bar();
foo.Baz();
foo = new CharlieTwo();
foo.Bar();
foo.Baz();
}
}
Before you read on, seriously: try to predict the output of this program.
Now actually run it. Did you get the output you expected? Where was your intuition wrong?
Do you see the difference between CharlieOne
and CharlieTwo
now? Re-implementing IFoo
in CharlieTwo
can cause the interface binding to pick up Bravo.Baz
even though Bravo
does not re-implement IFoo
!
And on the other hand: if you expected Bravo.Baz
to be assigned to the interface slot just because it exists, then you see how failing to re-implement an interface causes the code to be incorrect. For Bravo.Baz
to replace Alpha.IFoo.Baz
, Bravo
must re-implement IFoo
.
The takeaway here is: when you re-implement an interface, all the interface bindings are recomputed from scratch. This can cause semantic changes in your program, so only re-implement an interface when you mean to do so.
This also illustrates yet another form of the brittle base class failure. Suppose Bravo
does not have method Baz
when you write Charlie
. If you write Charlie
to re-implement IFoo
then the author of Bravo
adding Baz
afterwards -- perhaps the authors of Bravo
are on a different team at your company -- changes the interface bindings within Charlie
even if that is not what the authors of Bravo
intended.
For more information, see my article on the subject:
http://blogs.msdn.com/b/ericlippert/archive/2011/12/08/so-many-interfaces-part-two.aspx
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…