TTYF ~earlgrey の雑記~

主に自分用メモとか

VB でインターフェイスの明示的実装

この記事は、Visual Basic Advent Calendar 2016 の 17 日目のエントリーです。16 日目は mmYYmmdd さんの VBAHaskell での関数定義 でした。

今回紹介するネタは特に目新しいものではないのですが、VBインターフェイスの明示的実装方法を調べるときのググラビリティ向上のために選んでみました。もっとも英語でググる と I'm Feeling Lucky 一発で解答にたどり着けたりしますけど。

現状ググラビリティがもうひとつなのは、Microsoft がなぜか VB においてはインターフェイスの明示的実装という用語を使っていないからです。理由はよくわかりませんが...。

インターフェイスの明示的実装とは

そもそも明示的なインターフェイスの実装って何?ということを念のため確認しておくと、あるインターフェイスのメンバに対して、実装しているクラスの参照変数ではなく、インターフェイスの参照変数を通じてしか呼び出すことができないようにすることです。言葉だけだとちょっとわかりにくいですが、後でサンプルを出します。

どういうときに使うかというと、フレームワークやライブラリで呼び出すために必要なんだけど、ユーザーコードからは使ってほしくないメンバーを実装するときが多いでしょうか。例えば ICloneable とかですかね。詳しい指針は、古い文書ですが MSDN の解説 をご覧ください。

VB での書き方

VBインターフェイスの明示的実装を行うためには、実装するメンバを Private で修飾します。

Module Module1

    Sub Main()
        Dim one = New Getter()
        Dim ione = DirectCast(one, IGetOne)

        ' コンパイルエラー
        Console.WriteLine(one.GetOne())

        ' OK
        Console.WriteLine(ione.GetOne())
    End Sub

End Module

Interface IGetOne
    Function GetOne() As Integer
End Interface

Class Getter
    Implements IGetOne

    ' Private にすると明示的実装
    Private Function GetOne() As Integer Implements IGetOne.GetOne
        Return 1
    End Function
End Class

VB ならではの機能?

上記では明示的実装のために Private を使いましたが、Protected や Friend を指定することもできます。つまり、次のようなこともできます。

Module Module1

    Sub Main()
        Dim one = New Getter()
        Dim ione = DirectCast(one, IGetOne)

        ' コンパイルエラー
        Console.WriteLine(one.GetOne())

        ' OK
        Console.WriteLine(ione.GetOne())
    End Sub

End Module

Interface IGetOne
    Function GetOne() As Integer
End Interface

Class Getter
    Implements IGetOne

    ' Protected で明示的実装することもできる
    Protected Function GetOne() As Integer Implements IGetOne.GetOne
        Return 1
    End Function
End Class

Class Getter2
    Inherits Getter

    Sub action()
        ' OK
        Dim one = MyBase.GetOne()
    End Sub
End Class

この例は Protected ですが、正直あまり使いどころがわかりません。ただ、Friend だとそれなりに便利かも、というかフレームワークやライブラリで呼び出すときだけインターフェイスにキャストしなくても良いようにする、という目的だとむしろ Private を使うよりも適切かもしれません。

ちなみにちょっと試した限りでは、C# では明示的実装を行うとそのメンバは常に private 相当になり、protected や internal 相当で明示的実装をすることはできないっぽいので、VB ならではの機能、ということになります。