< Day Day Up > |
A type implements an interface by specifying the name of the interface in an Implements statement. There is no limit on the number of interfaces that a type can implement; a type can implement multiple interfaces in a single Implements statement or can contain multiple Implements statements. For example, the following code defines two classes, Square and Rectangle , which each implement the ISizeable interface and the IComparable interface. Class Square Implements ISizeable, IComparable ... End Class Class Rectangle Implements ISizeable Implements IComparable ... End Class When a type implements an interface, it must provide an implementation for each member of the interface. A type implements a member of an interface by adding an Implements clause on a type member that has the same signature (i.e., parameter list and return type) as the interface member. In the following example, the Square class provides an implementation for each member of the ISizeable interface. Class Square Implements ISizeable Private _Height, _Width As Integer Public ReadOnly Property Height() As Integer _ Implements ISizeable.Height Get Return _Height End Get End Property Public ReadOnly Property Width() As Integer _ Implements ISizeable.Width Get Return _Width End Get End Property Public Sub Resize(ByVal NewWidth As Integer, _ ByVal NewHeight As Integer) Implements ISizeable.Resize _Height = NewHeight _Width = NewWidth RaiseEvent Resized(NewWidth, NewHeight) End Sub Public Event Resized(ByVal NewWidth As Integer, _ ByVal NewHeight As Integer) Implements ISizeable.Resized End Class It is worth noting that the name of a member and the name of the interface member that it implements do not have to match, although they usually do. For example, the previous example could have been written instead as follows . Class Square Implements ISizeable Private _Height, _Width As Integer Public ReadOnly Property SquareHeight() As Integer _ Implements ISizeable.Height Get Return _Height End Get End Property Public ReadOnly Property SquareWidth() As Integer _ Implements ISizeable.Width Get Return _Width End Get End Property Public Sub SquareResize(ByVal NewWidth As Integer, _ ByVal NewHeight As Integer) Implements ISizeable.Resize _Height = NewHeight _Width = NewWidth RaiseEvent SquareResized(NewWidth, NewHeight) End Sub Public Event SquareResized(ByVal NewWidth As Integer, _ ByVal NewHeight As Integer) Implements ISizeable.Resized End Class The fact that the Square.SquareHeight method and the ISizeable.Height method have different names makes no difference when you are implementing the interface. It does affect how the type and interface are used, as will be discussed in a subsequent section.
Private Interface ImplementationOne thing to note is that the members of an interface are always Public even if the members implementing them are not. In other words, interface methods on a type can be called even if the members implementing them cannot be called ( assuming , of course, that the type itself is accessible). For example, the following class implements the ISizeable interface in such a way that the ISizeable methods can only be called through the interface. Class Square Implements ISizeable Private _Height, _Width As Integer Private ReadOnly Property Height() As Integer _ Implements ISizeable.Height Get Return _Height End Get End Property Private ReadOnly Property Width() As Integer _ Implements ISizeable.Width Get Return _Width End Get End Property Private Sub Resize(ByVal NewWidth As Integer, _ ByVal NewHeight As Integer) Implements ISizeable.Resize _Height = NewHeight _Width = NewWidth RaiseEvent Resized(NewWidth, NewHeight) End Sub Private Event Resized(ByVal NewWidth As Integer, _ ByVal NewHeight As Integer) Implements ISizeable.Resized End Class Module Test Sub Main() Dim s As Square = New Square() Dim i As ISizeable = s ' Error: Resize is not accessible s.Resize(10, 10) ' OK: Resize is always accessible through interface i.Resize(10, 10) End Sub End Module In the previous example, the Square class uses a private interface implementation to implement the ISizeable interface without exposing any of the interface methods directly. Private interface implementations are useful when a type wishes to implement an interface but not expose the methods as a part of the type. A common use of private interface implementation is to implement a general interface while providing a more specific version of the interface's methods. For example, a Point structure may implement the IComparable interface (which takes Object ) while exposing a CompareTo method that takes Point values. Structure Point Implements IComparable Private Function CompareTo(ByVal obj As Object) As Integer _ Implements IComparable.CompareTo ... End Function Public Function CompareTo(ByVal p As Point) As Integer ... End Function ... End Structure In this example, the CompareTo(Object) function is less desirable than the CompareTo(Point) method because converting a Point structure to Object would require boxing. However, there is still benefit in implementing the IComparable interface, since many Framework methods use it. A private interface implementation allows implementing the interface while only exposing the strongly typed CompareTo to code using the Point class directly. Event ImplementationWhen a type implements an interface event, the delegate type of the event in the interface must match the delegate type of the event in the type. When the delegate type is stated explicitly, this is relatively straightforward. Interface IClickable Event Click As EventHandler End Interface Class Square Implements IClickable Event Click As EventHandler Implements IClickable.Click End Class However, when an event implicitly defines its own delegate, things get more complicated. An event that implements an interface event but doesn't explicitly declare its delegate type picks up its delegate type from the interface event. Interface IClickable Event Click As EventHandler End Interface Class Square Implements IClickable Event Click(ByVal sender As Object, ByVal e As EventArgs) _ Implements IClickable.Click End Class In this example, the Square.Click event implicitly picks up its delegate type from IClickable.Click . So the underlying delegate type of Square.Click will be System.EventHandler and not an auto-generated ClickEventHandler type. Note that the parameters to the event still must match the arguments of the event delegate. If an event attempts to implement two events that use different delegate types, an error will occur because there is no way for an event to have two different delegate types. Interface IClickable Event Click(ByVal sender As Object, ByVal e As EventArgs) Event Release(ByVal sender As Object, ByVal e As EventArgs) End Interface Class Square Implements IClickable ' Error, delegate types conflict Event Click(ByVal sender As Object, ByVal e As EventArgs) _ Implements IClickable.Click, IClickable.Release End Class Even though IClickable.Click and IClickable.Release have the same parameters, they each declare their own implicit delegate type. When Square.Click attempts to implement both of the events, it cannot choose between the two delegate types, so an error results. |
< Day Day Up > |