Scrigroup - Documente si articole

     

HomeDocumenteUploadResurseAlte limbi doc
AccessAdobe photoshopAlgoritmiAutocadBaze de dateCC sharp
CalculatoareCorel drawDot netExcelFox proFrontpageHardware
HtmlInternetJavaLinuxMatlabMs dosPascal
PhpPower pointRetele calculatoareSqlTutorialsWebdesignWindows
WordXml


Interfaces - declarations, Interface members

C sharp



+ Font mai mare | - Font mai mic



Interfaces

An interface defines a contract. A class or struct that implements an interface must adhere to its contract. An interface may inherit from multiple base interfaces, and a class or struct may implement multiple interfaces.

Interfaces can contain methods, properties, events, and indexers. The interface itself does not provide implementations for the members that it defines. The interface merely specifies the members that must be supplied by classes or interfaces that implement the interface.



Interface declarations

An interface-declaration is a type-declaration (9.5) that declares a new interface type.

interface-declaration:
attributesopt interface-modifiersopt
interface identifier interface-baseopt interface-body ;opt

An interface-declaration consists of an optional set of attributes (17), followed by an optional set of interface-modifiers (13.1.1), followed by the keyword interface and an identifier that names the interface, optionally followed by an optional interface-base specification (13.1.2), followed by a interface-body (13.1.3), optionally followed by a semicolon.

Interface modifiers

An interface-declaration may optionally include a sequence of interface modifiers:

interface-modifiers:
interface-modifier
interface-modifiers interface-modifier

interface-modifier:
new
public
protected
internal

private

It is an error for the same modifier to appear multiple times in an interface declaration.

The new modifier is only permitted on nested interfaces. It specifies that the interface hides an inherited member by the same name, as described in 10.2.2.

The public, protected, internal, and private modifiers control the accessibility of the interface. Depending on the context in which the interface declaration occurs, only some of these modifiers may be permitted (3.5.1).

Base interfaces

An interface can inherit from zero or more interfaces, which are called the explicit base interfaces of the interface. When an interface has more than zero explicit base interfaces, then in the declaration of the interface, the interface identifier is followed by a colon and a comma separated list of base interface identifiers.

interface-base:
: interface-type-list

The explicit base interfaces of an interface must be at least as accessible as the interface itself (3.5.4). For example, it is an error to specify a private or internal interface in the interface-base of a public interface.

It is an error for an interface to directly or indirectly inherit from itself.

The base interfaces of an interface are the explicit base interfaces and their base interfaces. In other words, the set of base interfaces is the complete transitive closure of the explicit base interfaces, their explicit base interfaces, and so on. An interface inherits all members of its base interfaces. In the example

interface IControl

interface ITextBox: IControl

interface IListBox: IControl

interface IComboBox: ITextBox, IListBox

the base interfaces of IComboBox are IControl, ITextBox, and IListBox.

In other words, the IComboBox interface above inherits members SetText and SetItems as well as Paint.

A class or struct that implements an interface also implicitly implements all of the interface's base interfaces.

Interface body

The interface-body of an interface defines the members of the interface.

interface-body:

Interface members

The members of an interface are the members inherited from the base interfaces and the members declared by the interface itself.

interface-member-declarations:
interface-member-declaration
interface-member-declarations interface-member-declaration

interface-member-declaration:
interface-method-declaration
interface-property-declaration
interface-event-declaration
interface-indexer-declaration

An interface declaration may declare zero or more members. The members of an interface must be methods, properties, events, or indexers. An interface cannot contain constants, fields, operators, instance constructors, destructors, or types, nor can an interface contain static members of any kind.

All interface members implicitly have public access. It is an error for interface member declarations to include any modifiers. In particular, it is an error for an interface member to include any of the following modifiers: abstract, public, protected, internal, private, virtual, override, or static.

The example

public delegate void StringListEvent(IStringList sender);

public interface IStringList

event StringListEvent Changed;

string this[int index]
}

declares an interface that contains one each of the possible kinds of members: A method, a property, an event, and an indexer.

An interface-declaration creates a new declaration space (3.3), and the interface-member-declarations immediately contained by the interface-declaration introduce new members into this declaration space. The following rules apply to interface-member-declarations:

The name of a method must differ from the names of all properties and events declared in the same interface. In addition, the signature (3.6) of a method must differ from the signatures of all other methods declared in the same interface.

The name of a property or event must differ from the names of all other members declared in the same interface.

The signature of an indexer must differ from the signatures of all other indexers declared in the same interface.

The inherited members of an interface are specifically not part of the declaration space of the interface. Thus, an interface is allowed to declare a member with the same name or signature as an inherited member. When this occurs, the derived interface member is said to hide the base interface member. Hiding an inherited member is not considered an error, but it does cause the compiler to issue a warning. To suppress the warning, the declaration of the derived interface member must include a new modifier to indicate that the derived member is intended to hide the base member. This topic is discussed further in 3.7.1.2.

If a new modifier is included in a declaration that doesn't hide an inherited member, a warning is issued to that effect. This warning is suppressed by removing the new modifier.

Interface methods

Interface methods are declared using interface-method-declarations:

interface-method-declaration:
attributesopt
newopt return-type identifier ( formal-parameter-listopt ) ;

The attributes, return-type, identifier, and formal-parameter-list of an interface method declaration have the same meaning as those of a method declaration in a class (10.5). An interface method declaration is not permitted to specify a method body, and the declaration therefore always ends with a semicolon.

Interface properties

Interface properties are declared using interface-property-declarations:

interface-property-declaration:
attributesopt
newopt type identifier

interface-accessors:
attributesopt
get ;
attributesopt set ;
attributesopt get ; attributesopt set ;
attributesopt
set ; attributesopt get ;

The attributes, type, and identifier of an interface property declaration have the same meaning as those of a property declaration in a class (10.6).

The accessors of an interface property declaration correspond to the accessors of a class property declaration (10.6.2), except that the accessor body must always be a semicolon. Thus, the accessors simply indicate whether the property is read-write, read-only, or write-only.

Interface events

Interface events are declared using interface-event-declarations:

interface-event-declaration:
attributesopt
newopt event type identifier ;

The attributes, type, and identifier of an interface event declaration have the same meaning as those of an event declaration in a class (10.7).

Interface indexers

Interface indexers are declared using interface-indexer-declarations:

interface-indexer-declaration:
attributesopt
newopt type this [ formal-parameter-list ]

The attributes, type, and formal-parameter-list of an interface indexer declaration have the same meaning as those of an indexer declaration in a class (10.8).

The accessors of an interface indexer declaration correspond to the accessors of a class indexer declaration (10.8), except that the accessor body must always be a semicolon. Thus, the accessors simply indicate whether the indexer is read-write, read-only, or write-only.

Interface member access

Interface members are accessed through member access (7.5.4) and indexer access (7.5.6.2) expressions of the form I.M and I[A], where I is an instance of an interface type, M is a method, property, or event of that interface type, and A is an indexer argument list.

For interfaces that are strictly single-inheritance (each interface in the inheritance chain has exactly zero or one direct base interface), the effects of the member lookup (7.3), method invocation (7.5.5.1), and indexer access (7.5.6.2) rules are exactly the same as for classes and structs: More derived members hide less derived members with the same name or signature. However, for multiple-inheritance interfaces, ambiguities can occur when two or more unrelated base interfaces declare members with the same name or signature. This section shows several examples of such situations. In all cases, explicit casts can be included in the program code to resolve the ambiguities.

In the example

interface IList
{
int Count
}

interface ICounter

interface IListCounter: IList, ICounter

class C

}

the first two statements cause compile-time errors because the member lookup (7.3) of Count in IListCounter is ambiguous. As illustrated by the example, the ambiguity is resolved by casting x to the appropriate base interface type. Such casts have no run-time costs-they merely consist of viewing the instance as a less derived type at compile-time.

In the example

interface IInteger

interface IDouble

interface INumber: IInteger, IDouble

class C

}

the invocation n.Add(1) is ambiguous because a method invocation (7.5.5.1) requires all overloaded candidate methods to be declared in the same type. However, the invocation n.Add(1.0) is permitted because only IDouble.Add is applicable. When explicit casts are inserted, there is only one candidate method, and thus no ambiguity.

In the example

interface IBase

interface ILeft: IBase

interface IRight: IBase

interface IDerived: ILeft, IRight

class A

}

the IBase.F member is hidden by the ILeft.F member. The invocation d.F(1) thus selects ILeft.F, even though IBase.F appears to not be hidden in the access path that leads through IRight.

The intuitive rule for hiding in multiple-inheritance interfaces is simply this: If a member is hidden in any access path, it is hidden in all access paths. Because the access path from IDerived to ILeft to IBase hides IBase.F, the member is also hidden in the access path from IDerived to IRight to IBase.

Fully qualified interface member names

An interface member is sometimes referred to by its fully qualified name. The fully qualified name of an interface member consists of the name of the interface in which the member is declared, followed by a dot, followed by the name of the member. The fully qualified name of a member references the interface in which the member is declared. For example, given the declarations

interface IControl

interface ITextBox: IControl

the fully qualified name of Paint is IControl.Paint and the fully qualified name of SetText is ITextBox.SetText.

In the example above, it is not possible to refer to Paint as ITextBox.Paint.

When an interface is part of a namespace, the fully qualified name of an interface member includes the namespace name. For example

namespace System

}

Here, the fully qualified name of the Clone method is System.ICloneable.Clone.

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.

interface ICloneable

interface IComparable

class ListEntry: ICloneable, IComparable

public int CompareTo(object other)
}

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.

interface IControl

interface ITextBox: IControl

class TextBox: ITextBox
{
public void Paint()

public void SetText(string text)
}

Here, class TextBox implements both IControl and ITextBox.

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. For example

interface ICloneable

interface IComparable

class ListEntry: ICloneable, IComparable
{
object ICloneable.Clone()

int IComparable.CompareTo(object other)
}

Here, ICloneable.Clone and IComparable.CompareTo are explicit interface member implementations.

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

class MyFile: IDisposable

public void Close()
}

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 an error for an explicit interface member implementation to include access modifiers, as is it an error to include the abstract, virtual, override, or static modifiers.

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 particularly useful when a class or struct implements an internal interface that is of no interest to a consumer of the 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. Thus, in the following class

class Shape: ICloneable
{
object ICloneable.Clone()

int IComparable.CompareTo(object other) // invalid
}

the declaration of IComparable.CompareTo is invalid 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 is in error because ICloneable is not explicitly listed in the base class list of Ellipse.

The fully qualified name of an interface member must reference the interface in which the member was declared. Thus, in the declarations

interface IControl

interface ITextBox: IControl

class TextBox: ITextBox
{
void IControl.Paint()

void ITextBox.SetText(string text)
}

the explicit interface member implementation of Paint must be written as IControl.Paint.

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:

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.

An error occurs if implementations cannot be located for all members of all interfaces specified in the base class list of C. Note that 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.

In the example

interface ICloneable

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.

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. For example

interface IControl

interface IForm

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.

If a class or struct implements an interface that contains hidden members, then some members must necessarily be implemented through explicit interface member implementations. For example

interface IBase

}

interface IDerived: IBase

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()
}

When a class implements multiple interfaces that have the same base interface, there can be only one implementation of the base interface. In the example

interface IControl

interface ITextBox: IControl

interface IListBox: IControl

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.

The members of a base class participate in interface mapping. In the example

interface Interface1

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.

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. For example, in the declarations

interface IControl

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();

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. For example, rewriting the declarations above to

interface IControl

class Control: IControl
{
public virtual void Paint()
}

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();

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. For example

interface IControl

class Control: IControl

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.

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. For example, in the declarations

interface IControl

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 re-implementation in MyControl, which maps IControl.Paint onto MyControl.Paint.

Inherited public member declarations and inherited explicit interface member declarations participate in the interface mapping process for re-implemented interfaces. For example

interface IMethods

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.

When a class implements an interface, it implicitly also implements all of the 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. For example

interface IBase

interface IDerived: IBase

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.

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. For example

interface IMethods

abstract class C: IMethods

Here, the implementation of IMethods maps F and G onto abstract methods, which must be overridden in non-abstract classes that derive from C.

Note that explicit interface member implementations cannot be abstract, but explicit interface member implementations are of course permitted to call abstract methods. For example

interface IMethods

abstract class C: IMethods

void IMethods.G()

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.



Politica de confidentialitate | Termeni si conditii de utilizare



DISTRIBUIE DOCUMENTUL

Comentarii


Vizualizari: 1190
Importanta: rank

Comenteaza documentul:

Te rugam sa te autentifici sau sa iti faci cont pentru a putea comenta

Creaza cont nou

Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved