20.4 Interface implementations

Interfaces may be implemented by classes and structs. To indicate that a
class or struct implements an interface,
the interface identifier is included in the base class list of the class or
struct. [Example: For example:
interface ICloneable
{
object Clone();
}
interface IComparable
{
int CompareTo(object other);
}
class ListEntry: ICloneable, IComparable
{
public object Clone() {?}
public int CompareTo(object other) {?}
}
end example]
A class or struct that implements an interface also implicitly implements
all of the interface?s base interfaces.
This is true even if the class or struct doesn?t explicitly list all base
interfaces in the base class list. [Example: For
example:
interface IControl
{
void Paint();
}
interface ITextBox: IControl
{
void SetText(string text);
}
class TextBox: ITextBox
{
public void Paint() {?}
public void SetText(string text) {?}
}
Chapter 20 Interfaces
285
Here, class TextBox implements both IControl and ITextBox. end example]
20.4.1 Explicit interface member implementations
For purposes of implementing interfaces, a class or struct may declare
explicit interface member
implementations. An explicit interface member implementation is a method,
property, event, or indexer
declaration that references a fully qualified interface member name.
[Example: For example
interface ICloneable
{
object Clone();
}
interface IComparable
{
int CompareTo(object other);
}
class ListEntry: ICloneable, IComparable
{
object ICloneable.Clone() {?}
int IComparable.CompareTo(object other) {?}
}
Here, ICloneable.Clone and IComparable.CompareTo are explicit interface
member implementations. end
example]
[Example: In some cases, the name of an interface member may not be
appropriate for the implementing class, in
which case the interface member may be implemented using explicit interface
member implementation. A class
implementing a file abstraction, for example, would likely implement a
Close member function that has the
effect of releasing the file resource, and implement the Dispose method of
the IDisposable interface using
explicit interface member implementation:
interface IDisposable {
void Dispose();
}
class MyFile: IDisposable
{
void IDisposable.Dispose() {
Close();
}
public void Close() {
// Do what’s necessary to close the file


System.GC.SuppressFinalize(this);
}
}
end example]
It is not possible to access an explicit interface member implementation
through its fully qualified name in a
method invocation, property access, or indexer access. An explicit
interface member implementation can only be
accessed through an interface instance, and is in that case referenced
simply by its member name.
It is a compile-time error for an explicit interface member implementation
to include access modifiers, and it is a
compile-time error to include the modifiers abstract, virtual, override, or
static.
Explicit interface member implementations have different accessibility
characteristics than other members.
Because explicit interface member implementations are never accessible
through their fully qualified name in a
method invocation or a property access, they are in a sense private.
However, since they can be accessed through
an interface instance, they are in a sense also public.
Explicit interface member implementations serve two primary purposes:
? Because explicit interface member implementations are not accessible
through class or struct instances, they
allow interface implementations to be excluded from the public interface of
a class or struct. This is
C# LANGUAGE SPECIFICATION
286
particularly useful when a class or struct implements an internal interface
that is of no interest to a consumer
of that class or struct.
? Explicit interface member implementations allow disambiguation of
interface members with the same
signature. Without explicit interface member implementations it would be
impossible for a class or struct to
have different implementations of interface members with the same signature
and return type, as would it be
impossible for a class or struct to have any implementation at all of
interface members with the same
signature but with different return types.
For an explicit interface member implementation to be valid, the class or
struct must name an interface in its base
class list that contains a member whose fully qualified name, type, and
parameter types exactly match those of
the explicit interface member implementation. [Example: Thus, in the
following class
class Shape: ICloneable
{
object ICloneable.Clone() {?}
int IComparable.CompareTo(object other) {?} // invalid
}
the declaration of IComparable.CompareTo results in a compile-time error
because IComparable is not
listed in the base class list of Shape and is not a base interface of
ICloneable. Likewise, in the declarations
class Shape: ICloneable
{
object ICloneable.Clone() {?}
}
class Ellipse: Shape
{
object ICloneable.Clone() {?} // invalid
}
the declaration of ICloneable.Clone in Ellipse results in a compile-time
error because ICloneable is not
explicitly listed in the base class list of Ellipse. end example]
The fully qualified name of an interface member must reference the
interface in which the member was declared.
[Example: Thus, in the declarations
interface IControl
{
void Paint();
}
interface ITextBox: IControl
{
void SetText(string text);
}
class TextBox: ITextBox
{
void IControl.Paint() {?}
void ITextBox.SetText(string text) {?}
}
the explicit interface member implementation of Paint must be written as
IControl.Paint. end example]
20.4.2 Interface mapping
A class or struct must provide implementations of all members of the
interfaces that are listed in the base class
list of the class or struct. The process of locating implementations of
interface members in an implementing class
or struct is known as interface mapping.
Interface mapping for a class or struct C locates an implementation for
each member of each interface specified in
the base class list of C. The implementation of a particular interface
member I.M, where I is the interface in
which the member M is declared, is determined by examining each class or
struct S, starting with C and repeating
for each successive base class of C, until a match is located:
Chapter 20 Interfaces
287
? If S contains a declaration of an explicit interface member


implementation that matches I and M, then this
member is the implementation of I.M.
? Otherwise, if S contains a declaration of a non-static public member that
matches M, then this member is the
implementation of I.M.
A compile-time error occurs if implementations cannot be located for all
members of all interfaces specified in
the base class list of C. The members of an interface include those members
that are inherited from base
interfaces.
For purposes of interface mapping, a class member A matches an interface
member B when:
? A and B are methods, and the name, type, and formal parameter lists of A
and B are identical.
? A and B are properties, the name and type of A and B are identical, and A
has the same accessors as B (A is
permitted to have additional accessors if it is not an explicit interface
member implementation).
? A and B are events, and the name and type of A and B are identical.
? A and B are indexers, the type and formal parameter lists of A and B are
identical, and A has the same
accessors as B (A is permitted to have additional accessors if it is not an
explicit interface member
implementation).
Notable implications of the interface-mapping algorithm are:
? Explicit interface member implementations take precedence over other
members in the same class or struct
when determining the class or struct member that implements an interface
member.
? Neither non-public nor static members participate in interface mapping.
[Example: In the example
interface ICloneable
{
object Clone();
}
class C: ICloneable
{
object ICloneable.Clone() {?}
public object Clone() {?}
}
the ICloneable.Clone member of C becomes the implementation of Clone in
ICloneable because explicit
interface member implementations take precedence over other members. end
example]
If a class or struct implements two or more interfaces containing a member
with the same name, type, and
parameter types, it is possible to map each of those interface members onto
a single class or struct member.
[Example: For example
interface IControl
{
void Paint();
}
interface IForm
{
void Paint();
}
class Page: IControl, IForm
{
public void Paint() {?}
}
Here, the Paint methods of both IControl and IForm are mapped onto the
Paint method in Page. It is of
course also possible to have separate explicit interface member
implementations for the two methods. end
example]
C# LANGUAGE SPECIFICATION
288
If a class or struct implements an interface that contains hidden members,
then some members must necessarily
be implemented through explicit interface member implementations. [Example:
For example
interface IBase
{
int P { get; }
}
interface IDerived: IBase
{
new int P();
}
An implementation of this interface would require at least one explicit
interface member implementation, and
would take one of the following forms
class C: IDerived
{
int IBase.P { get {?} }
int IDerived.P() {?}
}
class C: IDerived
{
public int P { get {?} }
int IDerived.P() {?}
}
class C: IDerived
{
int IBase.P { get {?} }
public int P() {?}
}
end example]
When a class implements multiple interfaces that have the same base


interface, there can be only one
implementation of the base interface. [Example: In the example
interface IControl
{
void Paint();
}
interface ITextBox: IControl
{
void SetText(string text);
}
interface IListBox: IControl
{
void SetItems(string[] items);
}
class ComboBox: IControl, ITextBox, IListBox
{
void IControl.Paint() {?}
void ITextBox.SetText(string text) {?}
void IListBox.SetItems(string[] items) {?}
}
it is not possible to have separate implementations for the IControl named
in the base class list, the IControl
inherited by ITextBox, and the IControl inherited by IListBox. Indeed,
there is no notion of a separate
identity for these interfaces. Rather, the implementations of ITextBox and
IListBox share the same
implementation of IControl, and ComboBox is simply considered to implement
three interfaces, IControl,
ITextBox, and IListBox. end example]
The members of a base class participate in interface mapping. [Example: In
the example
Chapter 20 Interfaces
289
interface Interface1
{
void F();
}
class Class1
{
public void F() {}
public void G() {}
}
class Class2: Class1, Interface1
{
new public void G() {}
}
the method F in Class1 is used in Class2’s implementation of Interface1.
end example]
20.4.3 Interface implementation inheritance
A class inherits all interface implementations provided by its base classes.
Without explicitly re-implementing an interface, a derived class cannot in
any way alter the interface mappings it
inherits from its base classes. [Example: For example, in the declarations
interface IControl
{
void Paint();
}
class Control: IControl
{
public void Paint() {?}
}
class TextBox: Control
{
new public void Paint() {?}
}
the Paint method in TextBox hides the Paint method in Control, but it does
not alter the mapping of
Control.Paint onto IControl.Paint, and calls to Paint through class
instances and interface instances
will have the following effects
Control c = new Control();
TextBox t = new TextBox();
IControl ic = c;
IControl it = t;
c.Paint(); // invokes Control.Paint();
t.Paint(); // invokes TextBox.Paint();
ic.Paint(); // invokes Control.Paint();
it.Paint(); // invokes Control.Paint();
end example]
However, when an interface method is mapped onto a virtual method in a
class, it is possible for derived classes
to override the virtual method and alter the implementation of the
interface. [Example: For example, rewriting the
declarations above to
interface IControl
{
void Paint();
}
class Control: IControl
{
public virtual void Paint() {?}
}
C# LANGUAGE SPECIFICATION
290
class TextBox: Control
{
public override void Paint() {?}
}
the following effects will now be observed
Control c = new Control();


TextBox t = new TextBox();
IControl ic = c;
IControl it = t;
c.Paint(); // invokes Control.Paint();
t.Paint(); // invokes TextBox.Paint();
ic.Paint(); // invokes Control.Paint();
it.Paint(); // invokes TextBox.Paint();
end example]
Since explicit interface member implementations cannot be declared virtual,
it is not possible to override an
explicit interface member implementation. However, it is perfectly valid
for an explicit interface member
implementation to call another method, and that other method can be
declared virtual to allow derived classes to
override it. [Example: For example
interface IControl
{
void Paint();
}
class Control: IControl
{
void IControl.Paint() { PaintControl(); }
protected virtual void PaintControl() {?}
}
class TextBox: Control
{
protected override void PaintControl() {?}
}
Here, classes derived from Control can specialize the implementation of
IControl.Paint by overriding the
PaintControl method. end example]
20.4.4 Interface re-implementation
A class that inherits an interface implementation is permitted to
re-implement the interface by including it in the
base class list.
A re-implementation of an interface follows exactly the same interface
mapping rules as an initial
implementation of an interface. Thus, the inherited interface mapping has
no effect whatsoever on the interface
mapping established for the re-implementation of the interface. [Example:
For example, in the declarations
interface IControl
{
void Paint();
}
class Control: IControl
{
void IControl.Paint() {?}
}
class MyControl: Control, IControl
{
public void Paint() {}
}
the fact that Control maps IControl.Paint onto Control.IControl.Paint
doesn?t affect the reimplementation
in MyControl, which maps IControl.Paint onto MyControl.Paint. end example]
Chapter 20 Interfaces
291
Inherited public member declarations and inherited explicit interface
member declarations participate in the
interface mapping process for re-implemented interfaces. [Example: For
example
interface IMethods
{
void F();
void G();
void H();
void I();
}
class Base: IMethods
{
void IMethods.F() {}
void IMethods.G() {}
public void H() {}
public void I() {}
}
class Derived: Base, IMethods
{
public void F() {}
void IMethods.H() {}
}
Here, the implementation of IMethods in Derived maps the interface methods
onto Derived.F,
Base.IMethods.G, Derived.IMethods.H, and Base.I. end example]
When a class implements an interface, it implicitly also implements all of
that interface?s base interfaces.
Likewise, a re-implementation of an interface is also implicitly a
re-implementation of all of the interface?s base
interfaces. [Example: For example
interface IBase
{
void F();
}
interface IDerived: IBase
{
void G();
}
class C: IDerived
{
void IBase.F() {?}


void IDerived.G() {?}
}
class D: C, IDerived
{
public void F() {?}
public void G() {?}
}
Here, the re-implementation of IDerived also re-implements IBase, mapping
IBase.F onto D.F. end
example]
20.4.5 Abstract classes and interfaces
Like a non-abstract class, an abstract class must provide implementations
of all members of the interfaces that are
listed in the base class list of the class. However, an abstract class is
permitted to map interface methods onto
abstract methods. [Example: For example
interface IMethods
{
void F();
void G();
}
C# LANGUAGE SPECIFICATION
292
abstract class C: IMethods
{
public abstract void F();
public abstract void G();
}
Here, the implementation of IMethods maps F and G onto abstract methods,
which must be overridden in nonabstract
classes that derive from C. end example]
Explicit interface member implementations cannot be abstract, but explicit
interface member implementations are
of course permitted to call abstract methods. [Example: For example
interface IMethods
{
void F();
void G();
}
abstract class C: IMethods
{
void IMethods.F() { FF(); }
void IMethods.G() { GG(); }
protected abstract void FF();
protected abstract void GG();
}
Here, non-abstract classes that derive from C would be required to override
FF and GG, thus providing the actual
implementation of IMethods. end example]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值