Bagikan melalui


Membuat Antarmuka Generik Varian (Visual Basic)

Anda dapat mendeklarasikan parameter jenis generik dalam antarmuka sebagai kovarian atau kontravarian. Kovarian memungkinkan metode antarmuka untuk memiliki jenis pengembalian yang lebih turunan daripada yang ditentukan oleh parameter jenis generik. Kontravarian memungkinkan metode antarmuka untuk memiliki jenis argumen yang kurang diturunkan dari yang ditentukan oleh parameter generik. Antarmuka generik yang memiliki parameter jenis generik kovarian atau kontravarian disebut varian.

Nota

.NET Framework 4 memperkenalkan dukungan varians untuk beberapa antarmuka generik yang ada. Untuk daftar antarmuka varian di .NET Framework, lihat Varians di Antarmuka Generik (Visual Basic).

Mendeklarasikan Varian Antarmuka Generik

Anda dapat mendeklarasikan antarmuka generik varian dengan menggunakan in kata kunci dan out untuk parameter jenis generik.

Penting

ByRef parameter di Visual Basic tidak boleh berupa varian. Jenis nilai juga tidak mendukung varians.

Anda dapat mendeklarasikan kovarian parameter jenis generik dengan menggunakan out kata kunci. Jenis kovarian harus memenuhi kondisi berikut:

  • Jenis hanya digunakan sebagai jenis pengembalian metode antarmuka dan tidak digunakan sebagai jenis argumen metode. Ini diilustrasikan dalam contoh berikut, di mana jenis R dinyatakan kovarian.

    Interface ICovariant(Of Out R)
        Function GetSomething() As R
        ' The following statement generates a compiler error.
        ' Sub SetSomething(ByVal sampleArg As R)
    End Interface
    

    Ada satu pengecualian untuk aturan ini. Jika Anda memiliki delegasi generik kontravarian sebagai parameter metode, Anda dapat menggunakan jenis sebagai parameter tipe untuk delegasi generik tersebut. Ini diilustrasikan oleh jenis R dalam contoh berikut. Untuk informasi selengkapnya, lihat Varians di Delegasi (Visual Basic) dan Menggunakan Varians untuk Delegasi Generik Func dan Aksi (Visual Basic).

    Interface ICovariant(Of Out R)
        Sub DoSomething(ByVal callback As Action(Of R))
    End Interface
    
  • Jenis ini tidak digunakan sebagai batasan generik untuk metode antarmuka. Ini diilustrasikan dalam kode berikut.

    Interface ICovariant(Of Out R)
        ' The following statement generates a compiler error
        ' because you can use only contravariant or invariant types
        ' in generic constraints.
        ' Sub DoSomething(Of T As R)()
    End Interface
    

Anda dapat mendeklarasikan parameter jenis generik kontravarian dengan menggunakan in kata kunci. Jenis kontravarian hanya dapat digunakan sebagai jenis argumen metode dan bukan sebagai jenis pengembalian metode antarmuka. Jenis kontravarian juga dapat digunakan untuk batasan generik. Kode berikut menunjukkan cara mendeklarasikan antarmuka kontravarian dan menggunakan batasan generik untuk salah satu metodenya.

Interface IContravariant(Of In A)
    Sub SetSomething(ByVal sampleArg As A)
    Sub DoSomething(Of T As A)()
    ' The following statement generates a compiler error.
    ' Function GetSomething() As A
End Interface

Dimungkinkan juga untuk mendukung kovariansi dan kontravarians dalam antarmuka yang sama, tetapi untuk parameter jenis yang berbeda, seperti yang ditunjukkan dalam contoh kode berikut.

Interface IVariant(Of Out R, In A)
    Function GetSomething() As R
    Sub SetSomething(ByVal sampleArg As A)
    Function GetSetSomething(ByVal sampleArg As A) As R
End Interface

Di Visual Basic, Anda tidak dapat mendeklarasikan peristiwa dalam antarmuka varian tanpa menentukan jenis delegasi. Selain itu, antarmuka varian tidak dapat memiliki kelas, enum, atau struktur berlapis, tetapi dapat memiliki antarmuka berlapis. Ini diilustrasikan dalam kode berikut.

Interface ICovariant(Of Out R)
    ' The following statement generates a compiler error.
    ' Event SampleEvent()
    ' The following statement specifies the delegate type and
    ' does not generate an error.
    Event AnotherEvent As EventHandler

    ' The following statements generate compiler errors,
    ' because a variant interface cannot have
    ' nested enums, classes, or structures.

    'Enum SampleEnum : test : End Enum
    'Class SampleClass : End Class
    'Structure SampleStructure : Dim value As Integer : End Structure

    ' Variant interfaces can have nested interfaces.
    Interface INested : End Interface
End Interface

Menerapkan Antarmuka Generik Varian

Anda menerapkan antarmuka generik varian di kelas dengan menggunakan sintaks yang sama yang digunakan untuk antarmuka invarian. Contoh kode berikut menunjukkan cara mengimplementasikan antarmuka kovarian di kelas generik.

Interface ICovariant(Of Out R)
    Function GetSomething() As R
End Interface

Class SampleImplementation(Of R)
    Implements ICovariant(Of R)
    Public Function GetSomething() As R _
    Implements ICovariant(Of R).GetSomething
        ' Some code.
    End Function
End Class

Kelas yang mengimplementasikan antarmuka varian adalah tidak bervariasi. Misalnya, pertimbangkan kode berikut.

 The interface is covariant.
Dim ibutton As ICovariant(Of Button) =
    New SampleImplementation(Of Button)
Dim iobj As ICovariant(Of Object) = ibutton

' The class is invariant.
Dim button As SampleImplementation(Of Button) =
    New SampleImplementation(Of Button)
' The following statement generates a compiler error
' because classes are invariant.
' Dim obj As SampleImplementation(Of Object) = button

Memperluas Varian Antarmuka Generik

Ketika Anda memperluas antarmuka generik varian, Anda harus menggunakan kata kunci in dan out untuk menentukan secara eksplisit apakah antarmuka turunan mendukung varians. Kompilator tidak menyimpulkan perbedaan dari antarmuka yang diekstensikan. Misalnya, pertimbangkan antarmuka berikut.

Interface ICovariant(Of Out T)
End Interface

Interface IInvariant(Of T)
    Inherits ICovariant(Of T)
End Interface

Interface IExtCovariant(Of Out T)
    Inherits ICovariant(Of T)
End Interface

Dalam antarmuka Invariant(Of T), parameter jenis generik T bersifat invariant, sedangkan dalam IExtCovariant (Of Out T), parameter jenis bersifat kovarian, meskipun kedua antarmuka memperluas antarmuka yang sama. Aturan yang sama diterapkan ke parameter jenis generik kontravarian.

Anda dapat membuat antarmuka yang memperluas antarmuka di mana parameter jenis generik T bersifat kovarian dan antarmuka di mana parameter tersebut bersifat kontravarian, asalkan dalam antarmuka yang memperluas parameter jenis generik T tetap bersifat invariant. Ini diilustrasikan dalam contoh kode berikut.

Interface ICovariant(Of Out T)
End Interface

Interface IContravariant(Of In T)
End Interface

Interface IInvariant(Of T)
    Inherits ICovariant(Of T), IContravariant(Of T)
End Interface

Namun, jika parameter T jenis generik dinyatakan kovarian dalam satu antarmuka, Anda tidak dapat menyatakannya kontravarian dalam antarmuka yang diperluas, atau sebaliknya. Ini diilustrasikan dalam contoh kode berikut.

Interface ICovariant(Of Out T)
End Interface

' The following statements generate a compiler error.
' Interface ICoContraVariant(Of In T)
'     Inherits ICovariant(Of T)
' End Interface

Menghindari Ambiguitas

Ketika Anda menerapkan antarmuka generik varian, varians terkadang dapat menyebabkan ambiguitas. Ini harus dihindari.

Misalnya, jika Anda secara eksplisit menerapkan antarmuka generik varian yang sama dengan parameter jenis generik yang berbeda dalam satu kelas, itu dapat membuat ambiguitas. Pengkompilasi tidak menghasilkan kesalahan dalam kasus ini, tetapi tidak ditentukan implementasi antarmuka mana yang akan dipilih pada waktu proses. Ini dapat menyebabkan bug halus dalam kode Anda. Perhatikan contoh kode berikut.

Nota

Dengan Option Strict Off, Visual Basic menghasilkan peringatan kompilator ketika ada implementasi antarmuka yang ambigu. Dengan Option Strict On, Visual Basic menghasilkan kesalahan pengkompilasi.

' Simple class hierarchy.
Class Animal
End Class

Class Cat
    Inherits Animal
End Class

Class Dog
    Inherits Animal
End Class

' This class introduces ambiguity
' because IEnumerable(Of Out T) is covariant.
Class Pets
    Implements IEnumerable(Of Cat), IEnumerable(Of Dog)

    Public Function GetEnumerator() As IEnumerator(Of Cat) _
        Implements IEnumerable(Of Cat).GetEnumerator
        Console.WriteLine("Cat")
        ' Some code.
    End Function

    Public Function GetEnumerator1() As IEnumerator(Of Dog) _
        Implements IEnumerable(Of Dog).GetEnumerator
        Console.WriteLine("Dog")
        ' Some code.
    End Function

    Public Function GetEnumerator2() As IEnumerator _
        Implements IEnumerable.GetEnumerator
        ' Some code.
    End Function
End Class

Sub Main()
    Dim pets As IEnumerable(Of Animal) = New Pets()
    pets.GetEnumerator()
End Sub

Dalam contoh ini, tidak ditentukan bagaimana pets.GetEnumerator metode memilih antara Cat dan Dog. Ini dapat menyebabkan masalah dalam kode Anda.

Lihat juga