Visual Basic 初級講座 [改訂版]
VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

第28ー2回 インターフェース

2021/6/13

この記事が対象とする製品・バージョン

VB2019 Visual Basic 2019 対象です。
VB2017 Visual Basic 2017 対象です。
VB2015 Visual Basic 2015 対象です。
VB2013 Visual Basic 2013 対象です。
VB2012 Visual Basic 2012 対象です。
VB2010 Visual Basic 2010 対象です。
VB2008 Visual Basic 2008 対象ですが、動作しないサンプルもあります。
VB2005 Visual Basic 2005 対象ですが、動作しないサンプルもあります。
VB.NET 2003 Visual Basic.NET 2003 対象外ですがほとんどの説明があてはまるので参考になります。
VB.NET 2002 Visual Basic.NET (2002) 対象外ですがほとんどの説明があてはまるので参考になります。
VB6対応 Visual Basic 6.0 × 対象外です。

 

この記事は 後から追加したため、第28-2回という、中途半端な名称になってしまいました。

 

目次

 

1.インターフェース

1-1.インターフェース

インターフェースとはメソッド等の定義の集合体です。インターフェースではメソッド等の引数や型が定義されているだけであって、中身の処理は記述されません。インターフェースは単独で使用するものではなく、中身の処理をクラスで実装(記述)することで動作するようになります。

と書いても、全然イメージできないと思います。インターフェースとはどういうモノで、どういう風に役に立つのか順を追って説明します。

 

1-2.IDisposable インターフェース

まず、IDisposable (読み方:IDisposable=アイディスポーザブル)というインターフェースを例として取り上げてみます。

IDisposableインターフェースには Dispose というメソッドが1つだけ定義されています。

インターフェースでは、メソッドの名前や引数や型などは定義しますが、処理の中身は記述しませんので、IDisposalbeインターフェースのプログラムは次のようになっています。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Interface IDisposable

    Sub Dispose()

End Interface

実際にはIDisposableインターフェースはC#でプログラムされてるので、この例はVBに置き換えると上記のようなプログラムだと言う意味です。

 

フレームワークのクラスには Dispose メソッドを持つものがたくさんありますが、それらはすべて、この IDisposalbeインターフェースを実装しています。Disposeメソッドは終了処理を実行してくれるメソッドです。

たとえば、次のクラスは、どれもDisposeメソッドを持っています。

これらのクラスはそれぞれの機能にまったく関連がありませんが、終了処理が必要であるという点は共通しています。

この共通性を定義するのがインターフェースの役割です。

下記の図では、各クラスの代表的なメソッドとDisposeメソッドを抜粋してみました。Disposeメソッドはこのように横串で共通しているイメージです。

 

IDisposableインターフェースには、Disposeメソッドの中身は記述されていないので、Disposeメソッドが呼び出されたときに具体的にどのような終了処理を行うかは各クラスで定義します。この仕組みによって定義は共通だけで、処理はそれぞれのクラスで異なるという実装が可能になります。

メモ メモ  - Disposeについては第20回 クラスの作成 で説明しています。

VB クラスの作成

 

 

2.型としてのインターフェース

2-1.インターフェースを型として使ってみる

インターフェースは「型」であるという点で、インターフェースを使わないでただ単に名前や定義が同じメソッドをいろいろなクラスで実装するのとは大きな違いがあります。

型であるということは Dim x As xxxxx のように As xxxxxx の部分に指定できるということです。

だから、次のプログラムは有効です。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019


Dim test As IDisposable

しかし、インターフェースは定義の集合体であって、処理はなにも記述されていませんので、New をしたり、何かの処理を、この例の変数 test から呼び出すことはできません。

 

HttpClient クラスは IDisposable を実装するので、IDisposable型の変数に代入することができます。

次のプログラムは有効です。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim client As New Net.Http.HttpClient

Dim test As IDisposable = client

.NET Framework の場合、このプログラムをエラーなしで実行するには System.Net.Http への参照設定が必要です。

このプログラムでは、test. と入力すると、すべてのクラスで共通で使用できるEquals, GetHashCode, GetType, ToString の他は、 Dispose メソッドしか表示されません。

変数 test は IDisposable 型であり、IDisposalbe には Dispose メソッドしか定義されていないからです。

変数 test の実体は HttpClient 型のインスタンス なので、本当はこれ以外にもたくさんのメソッドやプロパティが使用できます。でも、変数 test 経由で直接呼び出せるのはこれに限定されてしまいます。

試しに client. と入力すると、本当に使用可能な全メンバーが表示されます。当然 Dispose もこの中にあります。

 

 

2-2.引数の型をインターフェースにする

インターフェースは型なので変数だけでなく、引数の型としても使用できます。

たとえば、次のメソッドはインターフェースである IDisposable型の引数を持ちます。

VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Sub EndObject(o As IDisposable)

    If o IsNot Nothing Then o.Dispose()
    End If

End Sub

このメソッドの引数には IDisposable インターフェースを実装するものならなんでも指定できます。

それが何であれ、このメソッドは Dispose メソッドしか呼び出さないので他の機能は関係ないわけです。

 

Disposeメソッドだとありがたみがないので、今度はもうちょっとわかりにくいけれども、もうちょっと役に立つ例を紹介しましょう。

List(Of T) や Dictionary(Of T) などのコレクションは、要素を列挙することが可能であり、この要素を列挙する機能は IEnumerable(Of T)インターフェースとして定義されています。

IEnumerable(Of T)インターフェースには、 GetEnumerator というメソッドが1つだけ定義されています。このメソッドは要素を列挙するためのオブジェクトを取得します。このオブジェクトは「列挙子」(Enumerator)と呼ばれます。

列挙子には次の要素を取得する MoveNextメソッドと、現在の要素を取得する Currentプロパティがあります。次の要素がない場合MoveNextメソッドは False を返します。

ちょっと練習してみましょう。列挙子を使うと次のように List からすべて値を取り出すことができます。

VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim namesList As New List(Of String)({"Apple", "Banana", "Cat", "Dog"})
Dim itor = namesList.GetEnumerator

While itor.MoveNext Debug.WriteLine(itor.Current)
End While

Debug.WriteLineで出力される場所

これを応用して、最もたくさん出現した項目を取得するプログラムを書いてみます。

たとえば、{"Apple", "Cat", "Banana", "Cat", "Apple", "Dog", "Cat"} というコレクションの場合、 Cat が最もたくさん出現したいます。

プログラムをメソッドとして記述すると次のようになります。

VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Private Function Mode(Of T)(source As IEnumerable(Of T)) As T

    Dim counts As New Dictionary(Of T, Integer) '項目と出現回数の一覧
    Dim maxItem As T '現在までに最多出現した項目 Dim maxCount As Integer '現在までに最多出現した項目の出現数

    Dim itor = source.GetEnumerator
    While itor.MoveNext '現在の項目が既に一覧に含まれている確認する
        If counts.ContainsKey(itor.Current) Then '一覧に含まれている場合は、出現数に 1 をたす counts(itor.Current) += 1 Else '一覧に含まれていない場合は、一覧に追加し、出現数を 1 にする counts(itor.Current) = 1 End If
'現在までの最多出現数をこの項目が上回っているかチェック If maxCount < counts(itor.Current) Then '上回っているなら、今の項目を最多出現項目として記録 maxCount = counts(itor.Current) maxItem = itor.Current
        End If

    End While
'最多出現項目を返す
    Return maxItem

End Function

このメソッドの定義が Mode(Of T) のようにジェネリックになっているのは、受け取る引数にList(Of String)や List(Of Integer) や Stack(Of Date)のようなジェネリックを想定しているからです。型パラメーターが何か事前にわからないので、メソッド側でも型パラメーターを定義することになります。実際に呼び出す場合は、VBが型推論してくれるので、型パラメーターに型を指定する必要はありません。

呼び出しは次のようになります。

VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim namesList As New List(Of String)({"Apple", "Cat", "Banana", "Cat", "Apple", "Dog", "Cat"})
Dim result As String = Mode(namesList)
Debug.WriteLine(result) ' Cat を出力します。

 

Modeメソッドの引数は IEnumerable(Of T)型です。インターフェースなので、このインターフェースを実装するものであればなんでも指定できます。

StringクラスもこのIEnumerable(Of T)を実装しているため、次のプログラムも有効です。

VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim value As String = "あめんぼ赤いなあえいうえおあお"
Dim result As String = Mode(value)

Debug.WriteLine(result) ' あ を出力します。

Stringクラスの列挙子は文字列に含まれる文字を1つずつ列挙します。この文字列では、「あ」が最多なので結果は「あ」になります。

 

このように「列挙する機能がある」という観点で、クラスを共通化して、同じ処理を実行できるところがインターフェースのメリットです。

名前が同じというだけのメソッドであれば、このような共通化はできません。

 

VB の ForEach ~ Next メソッドも IEnumerable インターフェースのGetEnumeratorメソッドを利用することで、どのようなオブジェクトであれ、列挙可能なものを列挙します。Using ~ End Using は IDisposable インターフェース の Dispose メソッドを利用することで、どのようなオブジェクトであれ、確実に終了処理を呼ぶという機能を実現しています。

 

 

3.インターフェースを作ってみる

3-1.インターフェースの定義

今度はインターフェースを作って、処理を実装してみましょう。

これから1つのインターフェスト、それを実装する3つのクラスを作ります。 実際にやってみる人は コンソールアプリケーション で試していただくようにお願いします。説明の中でコンソールアプリケーションの機能を使うからです。

 

今回は何かの文字列変換機能である Translate メソッド を持つインターフェース ITranslator を定義してみます。

たとえば、ひらがなを受け取ってカタカナに変換したり、日本語を受け取って英語に変換したりいろいろな変換機能が考えられます。

インターフェースを定義するには Interface ~ End Interface (読み方:Interface = インターフェース)を使用します。

インターフェースの名前は慣例的に英語の大文字の I (アイ) から始めることになっています。機能上はそうでない名前を付けることもできますが、私のプログラム人生の中で I から始まらないインターフェースは見たことがありません。 I から始めておくことが事実上必須というレベルです。

インターフェースを定義するだけならとても簡単です。次のようになります。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Interface ITranslator
    Function Translate(value As String) As String
End Interface

String型の引数を受け取って、String型の戻り値を返す Translateメソッドが定義されているということがお判りいただけると思います。処理内容がないため End Function は書きません。

 

3-2.インターフェースの実装

それでは、このインターフェースを使って、ひらがなをカタカナに変換するクラスを作ってみます。

専用のクラス KatakanaConverter を定義してみましょう。この段階ではまだインターフェースとは無関係です。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Class KatakanaTranslator
End Class

 インターフェースを実装するには、クラスの中の先頭で Implements キーワード (読み方:Implements = インプリメンツ)を使って、インターフェースを指定します。(初級講座では取り上げませんが、継承を指定する Inherits キーワードがある場合は、それよりは後に記述する必要があります。)

 

Visual Studio は Implements ITRanslator と入力して Enter を押すと、最低限必要なプログラムを自動的に生成してくれます。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Class KatakanaTranslator
    Implements ITranslator '←ここまで入力したら Enter キーを押します。

End Class

上の状態で最後に Enter を押すとVisual Studio の支援機能が働いて次のようなプログラムになります。

Visual Studioのバージョンによっては少し異なる場合があります。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Class KatakanaTranslator
   Implements ITranslator

    Public Function Translate(value As String) As String Implements ITranslator.Translate Throw New NotImplementedException() End Function
End Class

ITranslatorインターフェースを実装するということは、Translateメソッドを定義する必要があるので、Visual Studio が自動的に定義してあげますよということです。

自動生成される Translateメソッドの後ろには Implements ITranslator.Translate と記述されており、 ITranlatorインターフェースのTranslateメソッドの実装であることを示しています。インターフェースを実装する場合は、必ずこのように明示的にどのインターフェースのどのメソッドの実装なのかを示す必要があります。ただ単に名前や引数や型が一致しているだけのメソッドがあるだけでは、インターフェースの実装とはみなされません。

Tranlateメソッドの中身は Throw New NotImpelmentedException() となっています。これは「まだ実装されていない」という意味の例外を必ず発生させるプログラムです。この部分を置き換えて、このメソッドを完成させればよいわけです。

VBは日本語環境のWindowsで実行している場合に限って、ひらがなをカタカナに変換できる StrConv (読み方:エスティーアールコンブ?)というメソッドを使用できます。このメソッドは正しく動作する条件がいまいちわかりにくいので、私は重要なプログラムでは使用しないようにしていますが、今回のようにお手軽に試すのには十分です。

次のようになります。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Class KatakanaTranslator
   Implements ITranslator

    Public Function Translate(value As String) As String Implements ITranslator.Translate
     '↓.NET Framework で実行する場合、この RegisterProvider の行はコメントにしてください。
        System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance)
        Return StrConv(value,VbStrConv.Katakana)
End Function End Class

 

インターフェースを実装しているとは言え、普通のクラスとしても使えるので次のように呼び出すことができます。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim translator As New KatakanaTranslator
Dim result As String = translator.Translate("鏡の国のアリス")
Console.WriteLine(result) '鏡ノ国ノアリス

'Console.ReadLine() '←Enterを押すまでコンソールを閉じないようにします。

 

3-3.英語翻訳機能

インターフェースとは複数のクラスで共通して実装するから意味があるのであって、このクラスしか実装しないのであればメリットはありません。別の変換機能を持つクラスを作ってみましょう。

今度は日本語を英語に翻訳する EnglishTranslator クラスを作ってみます。本格的な翻訳機能を作る場合は、外部のサービスを呼び出すのが一般的です。たとえば、C#のものですがAzureのCognitive Serviceを使用する記事がここにあります。VBでも同じことができます。チュートリアル:WPF (C#) を使って翻訳アプリを作成する

今回は、単純に登録済みの単語を置き換えるだけの実装です。

次のようにしてみます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Class EnglishTranslator
    Implements ITranslator

    Dim dic As Dictionary(Of String, String)
    Public Sub New()
        dic = New Dictionary(Of String, String) From
       {{"雄略天皇", "Yuryaku Tennou"}, {"法隆寺", "Horyuji"}, {"日本の", "Japanese"},
        {"第21代", "21th"}, {"天皇", "emperor"}, {"お寺", "temple"}, {"木造", "wooden"},  {"建築物", "building"}, {"考古学上の", "On archaeology,"}, {"実在する", "existing"},
        {"想定のされうる", "possibility"}, {"最古の", "the oldest"}, {"である", ""},
        {"、", ""}, {"。", "."}, {"は", "is"}}
    End Sub

    Public Function Translate(value As String) As String Implements ITranslator.Translate
        For Each item In dic
            Dim japanese As String = item.Key
            Dim english As String = item.Value
            value = Replace(value, japanese, english & " ") Next
Return value
    End Function
End Class

日本語と対する英語を持つ Dictionary をコンストラクターで準備しておいて、Translateメソッドの内部では、辞書の項目を1個ずつReplaceメソッドで置き換えていくだけの処理です。

呼び出し例は次の通りです。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim translator As New EnglishTranslator
Dim result As String = translator.Translate("法隆寺は日本のお寺。実在する最古の木造建築物である。")
Console.WriteLine(result) 'Horyuji is Japanese temple . existing the oldest wooden building .
'Console.ReadLine() '←Enterを押すまでコンソールを閉じないようにします。

あらかじめ「法隆寺」とか「お寺」を Dictionary に組み込んでいる出来レースなので、こんなレベルでもなんとかなくそれっぽい英語に翻訳してくれます。この英語は正しい英語ではありませんが、意味は通じるのではないかなと思います。

 

3-4.Base64変換機能

もう1個作ってみましょう。文字列を Base64 (ベースろくじゅうよん) に変換する Base64Translator を作ってみます。

Base64とは主にメールやWebの世界で使われるエンコード方式で、安全に通信できる文字だけを使って情報を表現する方式です。人間にはわけのわからない文字に変換されます。Base64は一見、暗号化しているようにも見えますが、決まったルールで変換しているだけなのでBase64から普通の人間が読める情報に変換することは簡単にできます。

VBでは Convertクラスの ToBase64Stringメソッドを使えばBase64へのエンコードができるのですが、このメソッドは引数をバイト型の配列で与える必要があるので、事前に文字列をバイト型の配列に変換する必要があります。

文字列をバイト型の配列に変換するとどうなるかは、文字の符号化方式(≒文字コード)によって変わります。今回は符号化方式として標準的に使われている UTF-8 を使ってバイト型の配列に変換してから、Base64に変換するようにプログラムしてみます。

次のようになります。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Class Base64Translator
    Implements ITranslator

    Public Function Translate(value As String) As String Implements ITranslator.Translate
        Dim binary As Byte() = System.Text.Encoding.UTF8.GetBytes(value)
        Return Convert.ToBase64String(binary)
    End Function
End Class

実行するには次のようにします。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim translator As New Base64Translator
Dim result As String = translator.Translate("法隆寺")
Console.WriteLine(result) '5rOV6ZqG5a+6

'Console.ReadLine() '←Enterを押すまでコンソールを閉じないようにします。

実行すると、「5rOV6ZqG5a+6」と表示されます。これがUTF-8の「法隆寺」をBase64で表現したものということです。

 

3-5.インターフェースの活用

ITransratorインターフェースを実装するクラスが3つできたので、インターフェースが型であるという特性を活かしてプログラムしてみましょう。

コンソールアプリケーションを前提として、どのような変換処理を行うかをユーザーに選択してもらうようにします。

VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Sub Main(args As String())
    Dim translator = CreateTranslator()

    Console.WriteLine(translator.Translate("雄略天皇は日本の第21代天皇。考古学上の実在する想定のされうる最古の天皇である。"))
    Console.WriteLine(translator.Translate("法隆寺は日本のお寺。実在する最古の木造建築物である。"))
    'Console.ReadLine() '←Enterを押すまでコンソールを閉じないようにします。
End Sub

Private Function CreateTranslator() As ITranslator

   Do
        Console.WriteLine("KATAKANA または BASE64 または ENGLISH を入力してください。")
        Dim userInput As String = Console.ReadLine.ToUpper
If userInput = "KATAKANA" Then
            Return New KatakanaTranslator
        ElseIf userInput = "BASE64" Then
            Return New Base64Translator
        ElseIf userInput = "ENGLISH" Then
            Return New EnglishTranslator
        End If
    Loop

End Function

プログラムが開始して Main メソッドが呼び出されたら、すぐに CreateTranlatorメソッドを呼び出します。CreateTranslatorメソッド内ではユーザーに KATAKANA または BASE64 または ENGLISH を入力させて、該当するXXXXTranslator クラスのインスタンスを戻り値として返します。それぞれのクラスは ITranslatorインターフェースを実装しているので、戻り値の型は ITranslator とします。

Main側では返ってきたインスタンスを変数 translator に格納して、Translateメソッドを呼び出します。

このプログラムのポイントは、Mainメソッド内では、変数translatorの実体が KatakanaTranslator なのか EnglishTranslator なのか Base64Translator なのかわからない点です。わからなくても Translate メソッドを呼び出す ことはできるので、問題ないというわけです。

このようなプログラムを書けるかどうかが、初級プログラマーから中級プログラマーへのステップアップの鍵です。

 

最後に、このサンプルの全体を掲載しておきます。

VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Imports System

Module Program

    Sub Main(args As String())
    Dim translator = CreateTranslator()

        Console.WriteLine(translator.Translate("雄略天皇は日本の第21代天皇。考古学上の実在する想定のされうる最古の天皇である。"))
    Console.WriteLine(translator.Translate("法隆寺は日本のお寺。実在する最古の木造建築物である。"))
    'Console.ReadLine() '←Enterを押すまでコンソールを閉じないようにします。
    End Sub

    Private Function CreateTranslator() As ITranslator

    Do
        Console.WriteLine("KATAKANA または BASE64 または ENGLISH を入力してください。")
        Dim userInput As String = Console.ReadLine.ToUpper
If userInput = "KATAKANA" Then
                Return New KatakanaTranslator
        ElseIf userInput = "BASE64" Then
            Return New Base64Translator
            ElseIf userInput = "ENGLISH" Then
                Return New EnglishTranslator
        End If
        Loop End Function End Module Public Interface ITranslator

   Function Translate(value As String) As String

End Interface

Public Class KatakanaTranslator Implements ITranslator

    Public Function Translate(value As String) As String Implements ITranslator.Translate
        '↓.NET Framework で実行する場合、この RegisterProvider の行はコメントにしてください。
        System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance)
        Return StrConv(value, VbStrConv.Katakana)
    End Function
End Class

Public Class EnglishTranslator
    Implements ITranslator

    Dim dic As Dictionary(Of String, String)
    Public Sub New()
        dic = New Dictionary(Of String, String) From
        {{"雄略天皇", "Yuryaku Tennou"}, {"法隆寺", "Horyuji"}, {"日本の", "Japanese"},
        {"第21代", "21th"}, {"天皇", "emperor"}, {"お寺", "temple"}, {"木造", "wooden"},
        {"建築物", "building"}, {"考古学上の", "On archaeology,"}, {"実在する", "existing"},
        {"想定のされうる", "possibility"}, {"最古の", "the oldest"}, {"である", ""},
        {"、", ""}, {"。", "."}, {"は", "is"}}
    End Sub

    Public Function Translate(value As String) As String Implements ITranslator.Translate
        For Each item In dic
            Dim japanese As String = item.Key
            Dim english As String = item.Value
            value = Replace(value, japanese, english & " ") Next

        Return value
    End Function
End Class

Public Class Base64Translator
    Implements ITranslator

    Public Function Translate(value As String) As String Implements ITranslator.Translate
        Dim binary As Byte() = System.Text.Encoding.UTF8.GetBytes(value) Return Convert.ToBase64String(binary)
    End Function
End Class

 

メモ メモ  - インターフェースとは何か? USB と同じです。

パソコンやスマホなどに USB がついていることが良くあります。いろいろな機器を簡単に接続して、便利な機能を使える優れものです。

しかし、USB自体はただの穴で、何が接続されるかは事前にわかりません。

これはまさにインターフェースです。

VBのインターフェース自体はただのメソッドの定義で、どんな処理が実装されるかは事前にわかりません。

USB や HDMI などパソコンについている口のことを「インターフェース」と呼ぶのは偶然ではなく、同じ概念のものだからです。

だから、インターフェースがいったい何なのかわからなくなったら、USBのプログラム版だと思うと理解しやすいかもしれません。口だけ先に作ってあるんです。

 

4.Tips

4-1.インターフェースの継承

インターフェースには複数のメソッドを定義することもできますし、プロパティやイベントを定義することもできます。

インターフェースはインターフェースを継承できるので、たくさんのメソッドが定義されている巨大なインターフェースを作るのではなく、役割が細分化された細かいインターフェースをたくさん作る方が柔軟性があり優れています。

インターフェースがインターフェースを継承するには Inherits キーワードを使用します。

下記の例では InterfaceC が InterfaceA と InterfaceB を継承しています。

ClassTestクラスは InterfaceC だけを Implements していますが、A と B のメソッドも実装することになります。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Interface InterfaceA
    Sub MethodA()
End Interface

Public Interface InterfaceB
    Sub MethodB()
End Interface

Public Interface InterfaceC
    Inherits InterfaceA, InterfaceB

    Sub MethodC()
End Interface

Public Class ClassTest
    Implements InterfaceC

    Public Sub MethodA() Implements InterfaceA.MethodA
        Throw New NotImplementedException()
    End Sub

    Public Sub MethodB() Implements InterfaceB.MethodB
        Throw New NotImplementedException()
    End Sub

    Public Sub MethodC() Implements InterfaceC.MethodC
        Throw New NotImplementedException()
    End Sub
End Class

 

4-2.複数のインターフェースの実装

クラス自身が複数のインターフェースを実装することもできます。

複数のインターフェースを実装するには Implements の後ろにカンマで区切ってインターフェースを指定します。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Class ClassTest
    Implements InterfaceA, InterfaceB

    Public Sub MethodA() Implements InterfaceA.MethodA
        Throw New NotImplementedException()
    End Sub

    Public Sub MethodB() Implements InterfaceB.MethodB
        Throw New NotImplementedException()
    End Sub
End Class

複数のインターフェースを実装すると、メソッド名など名前が重複してしまう場合があるので、クラス側では実装時にメソッド等の名前を変更することもできます。

たとえば、Cloneメソッド(読み方:Clone=クローン)を定義している IClonableインターフェース(読み方:IClonable=アイクローナブル)を実装するけれども、メソッド名は Copy にするということができます。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Public Class CloneTest
    Implements ICloneable

    Public Function Copy() As Object Implements ICloneable.Clone
        Debug.WriteLine("Copyが呼び出されました。")
        Return New CloneTest
    End Function
End Class

Debug.WriteLineで出力される場所

次のように Clone メソッドを呼び出すと、実際に呼び出されるのは Copyメソッドです。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim test As New CloneTest
Dim ifTest As ICloneable = test

ifTest.Clone() 'ここで Copy メソッドが呼び出されます。

この例では複数のインターフェースを実装しているわけではないので、名前を変えることはお勧めしません。混乱のもとになるだけです。

ただ、サンプルがシンプルになるので説明用の例として取り上げました。

 

フレームワークのクラスにも複数のインターフェースを実装しているクラスが多数あります。Microsoft Docsのリファレンスを確認すると、クラスがどんなインターフェースを実装しているのかわかります。

たとえば、下記の String クラスのリファレンスを見ると、String クラスがIEnumerable(Of Char)、IEnumerable、 IComparable、 IComparable(Of String)、IConvertible、 IEquatable(Of String)、 ICloneableの7個のインターフェースを実装していることがわかります。

String クラス (System) | Microsoft Docs

 

4-3.実装しているインターフェースの確認方法

クラスがあるインターフェースを実装しているかは TypeOf ... Is ... で判断できます。

たとえば、次の例では List(Of String)が IListインターフェースと IEnumerable(Of String)を実装していることを判断できます。

VB2002 VB2003 VB2005 VB2008 VB2010 VB2012 VB2013 VB2015 VB2017 VB2019

Dim list As New List(Of String)

If TypeOf list Is IList Then
    Debug.WriteLine("IListを実装しています。")
End If

If TypeOf list Is IEnumerable(Of String) Then
    Debug.WriteLine("IEnumrable(Of String)を実装しています。")
End If

これを利用して、クラスに何か目印をつける目的で何のメンバーも定義されていないインターフェースをImplementsすることがあります。こうしておくことで、そのインターフェースを持っているクラスだけ特別扱いするプログラムが記述できるようになります。このような目印として使うインターフェースをマーカーインターフェースと呼びます。

条件を付けて分岐する目印としては属性の方が柔軟で使いやすく、意味的にも目印の役割なので、マーカーインターフェースよりも属性を使う方が一般的です。

初級講座 第32回 モジュール で説明する拡張メソッド向けの目印としてインターフェースを付ける場合もあります。これは属性にはできないのでインターフェースを使うことに意義があります。