An interface is similar to a class, but it provides a specification rather than an implementation for its members. An interface is special in the following ways:
Interface members are all implicitly abstract. In contrast, a class can provide both abstract members and concrete members with implementations.
A class (or struct) can implement multiple
interfaces. In contrast, a class can inherit from only a
single class, and a struct cannot inherit at all
(aside from deriving from System.ValueType
).
An interface declaration is like a class declaration, but it provides no implementation for its members, since all its members are implicitly abstract. These members will be implemented by the classes and structs that implement the interface. An interface can contain only methods, properties, events, and indexers, which noncoincidentally are precisely the members of a class that can be abstract.
Here is a slightly simplified version of the IEnumerator
interface, defined in System.Collections
:
public interface
IEnumerator
{
bool MoveNext();
object Current { get; }
}
Interface members are always implicitly public and cannot declare an
access modifier. Implementing an interface means providing a public
implementation for all its
members:
internal class Countdown : IEnumerator { int count = 11; public bool MoveNext() { return count-- > 0 ; } public object Current { get { return count; } } }
You can implicitly cast an object to any interface that it implements:
IEnumerator e
= new Countdown();
while (e.MoveNext())
Console.Write (e.Current); // 109876543210
Interfaces may derive from other interfaces. For instance:
public interface IUndoable { void Undo(); } public interface IRedoable : IUndoable { void Redo(); }
IRedoable
“inherits” all the
members of IUndoable
.
Implementing multiple interfaces can sometimes result in a collision between member signatures. You can resolve such collisions by explicitly implementing an interface member. For example:
interface I1 { void Foo(); }
interface I2 { int Foo(); }
public class Widget : I1, I2
{
public void Foo() // Implicit implementation
{
Console.Write ("Widget's implementation of I1.Foo");
}
int I2.Foo
() // Explicit implementation of I2.Foo
{
Console.Write ("Widget's implementation of I2.Foo");
return 42;
}
}
Because both I1
and I2
have conflicting Foo
signatures, Widget
explicitly implements I2
’s Foo
method. This lets the two methods coexist in one class. The only way to
call an explicitly implemented member is to cast to its
interface:
Widget w = new Widget(); w.Foo(); // Widget's implementation ofI1
.Foo ((I1)w).Foo(); // Widget's implementation ofI1
.Foo ((I2)w).Foo(); // Widget's implementation ofI2
.Foo
Another reason to explicitly implement interface members is to
hide members that are highly specialized and distracting to a type’s
normal use case. For example, a type that implements ISerializable
would typically want to avoid
flaunting its ISerializable
members unless
explicitly cast to that interface.
An implicitly implemented interface member is, by default,
sealed. It must be marked virtual
or
abstract
in the base class in order
to be overridden: calling the interface member through either the base
class or the interface then calls the subclass’s implementation.
An explicitly implemented interface member cannot be marked
virtual
, nor can it be overridden in
the usual manner. It can, however, be
reimplemented.
A subclass can reimplement any
interface member already implemented by a base class.
Reimplementation hijacks a member implementation (when called through
the interface) and works whether or not the member is virtual
in the base class.
In the following example, TextBox
implements IUndo.Undo
explicitly, and so it cannot be marked as
virtual
. In order to “override” it,
RichTextBox
must reimplement IUndo
’s Undo
method:
public interface IUndoable { void Undo(); }
public class TextBox : IUndoable
{
void IUndoable.Undo()
{ Console.WriteLine ("TextBox.Undo"); }
}
public class RichTextBox : TextBox, IUndoable
{
public new void Undo()
{ Console.WriteLine ("RichTextBox.Undo"); }
}
Calling the reimplemented member through the interface calls the subclass’s implementation:
RichTextBox r = new RichTextBox(); r.Undo(); // RichTextBox.Undo ((IUndoable)r).Undo(); // RichTextBox.Undo
In this case, Undo
is
implemented explicitly. Implicitly implemented members can also be
reimplemented, but the effect is nonpervasive in that calling the member
through the base class invokes the base implementation.