Section 4 access interfaces
Access to interface members
The rules for calling interface methods and accessing using index indicators are the same as those in the class. If the name of the underlying Member is the same as that of the inherited high-level member, the underlying Member will overwrite the high-level member with the same name. However, because the interface supports multi-inheritance, in multi-inheritance, if the two parent interfaces contain members with the same name, this produces ambiguity (this is one of the reasons why the multi-Inheritance Mechanism of classes is canceled in C #). An explicit definition is required:
Using System;
Interface ISequence {
Int Count {get; set ;}
}
Interface IRing {
Void Count (int I );
}
Interface IRingSequence: ISequence, IRing {}
Class CTest {
Void Test (IRingSequence rs ){
// Rs. Count (1); error, Count has two meanings
// Rs. Count = 1; error. Count is ambiguous.
(ISequence) rs). Count = 1; // correct
(IRing) rs). Count (1); // call IRing. Count correctly
}
}
In the above example, the first two statements rs. count (1) and rs. count = 1 produces ambiguity, which leads to compilation errors. Therefore, you must explicitly assign the parent interface type to rs. This assignment does not incur any additional overhead during runtime.
Let's look at the following example:
Using System;
Interface IInteger {
Void Add (int I );
}
Interface IDouble {
Void Add (double d );
}
Interface INumber: IInteger, IDouble {}
Class CMyTest {
Void Test (INumber Num ){
// Num. Add (1); Error
Num. Add (1.0); // correct
(IInteger) n). Add (1); // correct
(IDouble) n). Add (1); // correct
}
}
Calling Num. Add (1) results in ambiguity, because the parameter types of candidate overload methods are applicable. However, call Num. add (1.0) is allowed because 1.0 is a floating point parameter type and method IInteger. the parameter types of Add () are inconsistent, and only IDouble is used. add is applicable. However, as long as an explicit assignment is added, there will be no ambiguity.
The problem of multi-inheritance of interfaces also leads to access issues for members. For example:
Interface IBase {
Void FWay (int I );
}
Interface ILeft: IBase {
New void FWay (int I );
}
Interface IRight: IBase
{Void G ();}
Interface IDerived: ILeft, IRight {}
Class CTest {
Void Test (IDerived d ){
D. FWay (1); // call ILeft. FWay
(IBase) d). FWay (1); // call IBase. FWay
(ILeft) d). FWay (1); // call ILeft. FWay
(IRight) d). FWay (1); // call IBase. FWay
}
}
In the above example, the method IBase. FWay is overwritten by the ILeft member method FWay In the derived interface Ileft. Therefore, the call to d. FWay (1) is actually called. Although from the inheritance path IBase-> IRight-> IDerived, The ILeft. FWay method is not overwritten. Keep this in mind: once a Member is overwritten, all access requests to it will be overwritten and the member will be "intercepted.
Class-to-interface implementation
As we have mentioned earlier, the interface definition does not include the implementation part of the method. Interfaces can be implemented through classes or structures. We mainly introduce how to implement interfaces through classes. When using a class to implement an interface, the interface name must be included in the base class list in the class definition.
The following example shows how to implement interfaces using classes. ISequence is a queue interface that provides the Add () method for adding objects to the end of the queue. IRing is a circular table interface, the Insert (object obj) method is provided to Insert objects into the ring, and the Insert position is returned by the method. RingSquence class implements the ISequence and IRing interfaces.
Using System;
Interface ISequence {
Object Add ();
}
Interface ISequence {
Object Add ();
}
Interface IRing {
Int Insert (object obj );
}
Class RingSequence: ISequence, IRing
{
Public object Add (){...}
Public int Insert (object obj ){...}
}
If a class implements an interface, the class also implicitly inherits all the parent interfaces of the interface, regardless of whether these parent interfaces are listed in the base class table defined by the class. See the following example:
Using System;
Interface IControl {
Void Paint ();
}
Interface ITextBox: IControl {
Void SetText (string text );
}
Interface IListBox: IControl {
Void SetItems (string [] items );
}
Interface IComboBox: ITextBox, IListBox {}
Here, the IcomboBox interface inherits ItextBox and IlistBox. TextBox class not only implements the interface ITextBox, but also implements the parent interface IControl of the interface ITextBox.
We have seen that a class can implement multiple interfaces. Let's look at the following example:
Interface IDataBound {
Void Bind (Binder B );
}
Public class EditBox: Control, IControl, IDataBound {
Public void Paint ();
Public void Bind (Binder B ){...}
}
The class EditBox derives from the class Control and implements Icontrol and IdataBound. In the previous example, the Paint method in the Icontrol interface and the Bind method in the IdataBound interface are implemented by the Public Member in the EditBox class. C # provides an alternative way to implement these methods, so that these classes can be executed without setting these Members to the public. The interface member can be implemented with a valid name. For example, the EditBox class can be implemented by changing the Icontrol. Paint and IdataBound. Bind methods.
Public class EditBox: IControl, IDataBound {
Void IControl. Paint (){...}
Void IDataBound. Bind (Binder B ){...}
}
Because each member is implemented by an external interface member, the member implemented by this method is called an external interface member. External interface members can only be called through interfaces. For example, the EditBox implementation in the Paint method can be called only by creating the Icontrol interface.
Class Test {
Static void Main (){
EditBox editbox = new EditBox ();
Editbox. Paint (); // error: no Paint event in EditBox
IControl control = editbox;
Control. Paint (); // call the EditBox Paint event
}
}
In the preceding example, the EditBox class inherits from the Control class and implements the IControl and IDataBound interfaces at the same time. The Paint method in EditBox comes from the IControl interface, and the Bind method comes from the IDataBound interface. Both methods are implemented as public members in the EditBox class. Of course, in C #, we can also choose not to implement interfaces as public members.
If each member clearly points out the implemented interface, the implemented interface is called an explicit interface member (explicit interface member ). In this way, we can rewrite the above example:
Public class EditBox: IControl, IDataBound {
Void IControl. Paint (){...}
Void IDataBound. Bind (Binder B ){...}
}
Explicit interface members can only be called through interfaces. For example:
Class CTest {
Static void Main (){
EditBox editbox = new EditBox ();
Editbox. Paint (); // error: Different Methods
IControl control = editbox;
Control. Paint (); // call the EditBox Paint Method
}
}
The call to editbox. Paint () in the above Code is incorrect, because editbox itself does not provide this method. Control. Paint () is the correct method of calling.
Note: The interface itself does not provide the Implementation of the defined members. It only describes these members. These members must rely on the support of the class or other interfaces that implement the interface.
Now that we know how to access the interface, we also need to know how to implement the interface and how to implement the C # interface, please refer to the next section-implementation Interface
Class-to-interface implementation
As we have mentioned earlier, the interface definition does not include the implementation part of the method. Interfaces can be implemented through classes or structures. We mainly introduce how to implement interfaces through classes. When using a class to implement an interface, the interface name must be included in the base class list in the class definition.
The following example shows how to implement interfaces using classes. ISequence is a queue interface that provides the Add () method for adding objects to the end of the queue. IRing is a circular table interface, the Insert (object obj) method is provided to Insert objects into the ring, and the Insert position is returned by the method. RingSquence class implements the ISequence and IRing interfaces.
Using System;
Interface ISequence {
Object Add ();
}
Interface ISequence {
Object Add ();
}
Interface IRing {
Int Insert (object obj );
}
Class RingSequence: ISequence, IRing
{
Public object Add (){...}
Public int Insert (object obj ){...}
}
If a class implements an interface, the class also implicitly inherits all the parent interfaces of the interface, regardless of whether these parent interfaces are listed in the base class table defined by the class. See the following example:
Using System;
Interface IControl {
Void Paint ();
}
Interface ITextBox: IControl {
Void SetText (string text );
}
Interface IListBox: IControl {
Void SetItems (string [] items );
}
Interface IComboBox: ITextBox, IListBox {}
Here, the IcomboBox interface inherits ItextBox and IlistBox. TextBox class not only implements the interface ITextBox, but also implements the parent interface IControl of the interface ITextBox.
We have seen that a class can implement multiple interfaces. Let's look at the following example:
Interface IDataBound {
Void Bind (Binder B );
}
Public class EditBox: Control, IControl, IDataBound {
Public void Paint ();
Public void Bind (Binder B ){...}
}
The class EditBox is derived from the class Control and implements Icontrol and IdataB.