Saturday, October 18, 2008

Implementing interfaces in VB.Net

In this post I'll talk about VB's explicit interface implementation and how to best exploit the power this brings. I guess that it's a well known fact that interface implementation in VB is explicit but what does that mean really? It simply means that to implement an interface in a class the developer has to explicitly declare what members of the class implements the members of the interface. C# also has the ability to explicitly implement interfaces but it supports implicit interface implementation too which lets you implement an interface by declaring members with the same names and signatures as those of the interface. To implement the IDisposable interface implicitly we'd write the following:

public class Foo : IDisposable
{
    public void Dispose()
    {
        // Implementation here...
    }
}

The developer never tells the compiler that the method named "Dispose" implements the method "Dispose" of the IDisposable interface, the compiler figures this out by comparing the name and the signature of the method. To explicitly implement an interface in C# we'd write the following instead:

public class Foo : IDisposable
{
    void IDisposable.Dispose()
    {
        // Implementation here...
    }
}

In this implementation we explicitly say that the "Dispose" method implements the "Dispose" method of the interface IDisposable, note that there is no scope declared for this method, this is because it's only accessible through the interface. If you held an instance of the class "Foo" you would not be able to invoke the Dispose method without casting the instance to IDisposable.

Foo foo = new Foo();

foo.Dispose(); // will not compile
(foo as IDisposable).Dispose(); // will compile

As seen here this means that a method that implements an interface method must have the same name as the interface method and be public OR have no name at all and be private (explicit implementation). In VB on the other hand where implementation is always explicit we have a lot more freedom regarding naming and scope. For example a method implementing an interface method can have any scope (Private, Protected, Friend or Public) and also any name. Oh, well, any valid name that is.

Public Class Foo
    Implements IDisposable

    Public Sub ThisMethodIsNotNamedDispose() Implements IDisposable.Dispose
        ' Implementation here...
    End Sub

End Class

Now we have a public method called something completely different than "Dispose" but still implementing the "Dispose" method, if you were to cast an instance of the Foo class to the IDisposable interface and call the "Dispose" method on it the method "ThisMethodIsNotNamedDispose" would be invoked. As I said earlier an implementing method can have any scope, the method "ThisMethodIsNotNamedDispose" could just as well have been made private for example and we would end up with a situation very similar to the C# way of explicitly implementing interfaces. One very big difference though is that from within the class Foo you'd be able to call the method "ThisMethodIsNotNamedDispose" even though it's private, in C# however you can never call an explicit member implementation without casting to the interface, not even from within the implementing class itself.

Another cool thing about VB's explicit interface implementation is that a single method or property can implement methods or properties from multiple interfaces at the same time.

Public Class Foo
    Implements ICollection, ICountable

    '...

    Public ReadOnly Property Count() As Integer Implements ICollection.Count, ICountable.Count
        Get
            Return theCount
        End Get
    End Property

    '...

End Class

Public Interface ICountable
    ReadOnly Property Count() As Integer
End Interface

Interface implementation is one of the very few areas where I think VB outshines C# (XML-literals being the other area).

I think that hiding the methods of the interface in the public interface of the class (by explicitly implement the interface in C# and setting a non public scope in VB) is something that should be sparsely used. I use it only when a method makes no sense when the concrete type is known. For example if you create a LinkedList that implements the ICollection(T) interface there is really no need to ever call the "IsReadOnly" property when you know that you're holding a LinkedList that is never read only, this interface property should be hidden from the public interface of the class.

I've used the IDisposable interface as an example here but I would strongly advice against ever hiding the "Dispose" method of this interface in production code.

5 comments:

  1. Wonderful blog post.

    One quick comment:
    "I think that hiding the methods of the interface in the public interface of the class (by explicitly implement the interface in C# and setting a non public scope in VB) is something that should be sparsely use"

    I disagree. I use explicit interface implentations often to ensure developers cannot directly use a concrete implementation of an interface. This is particular important when you want your developers to use dependency injection conventions (using explicit interfaces makes it hard to use the concrete implemenation directly). I guess making the vb.net method private would accomplish this enforcement...haven't tried it though.

    ReplyDelete
  2. If the class you're implementing is never supposed to be used other than through the interface I can agree with you, but if the class is part of an API or supposed to be instantiated and used I strongly disagre.

    ReplyDelete
  3. Another area where VB outshines C# is Events, of course.

    ReplyDelete
  4. A discussion of the pros and cons of implicit and explicit interface implementation is not complete without the following:

    If an interface should partially be implemented by the class, and partially by its base class, explicit implementation gets ugly. You have to implement all interface members in the class and map some of them to the base class. Example:
    Public Shaddows ReadOnly Property Count() As Integer Implements ICollection.Count
    Get
    Return MyBase.Count
    End Get
    End Property
    If an Event is defined in the interface, it gets even uglier, because you have to write code to map the AddHandler, RemoveHandler and RaiseEvent methods.
    With implicit implementation this happens automatically without the need to write code.

    ReplyDelete