Aracılığıyla paylaş


Uzantı Yöntemleri (Visual Basic)

Uzantı yöntemleri, geliştiricilerin yeni türetilmiş bir tür oluşturmadan önceden tanımlanmış olan veri türlerine özel işlevler eklemesini sağlar. Uzantı yöntemleri, mevcut türün örnek yöntemiymiş gibi çağrılabilecek bir yöntem yazmayı mümkün hale getirir.

Açıklamalar

Uzantı yöntemi yalnızca bir Sub yordam veya Function yordam olabilir. Uzantı özelliği, alanı veya olayı tanımlayamazsınız. Tüm uzantı yöntemleri ad alanından uzantı özniteliğiyle <Extension>System.Runtime.CompilerServices işaretlenmeli ve bir Modülde tanımlanmalıdır. Bir uzantı yöntemi bir modülün dışında tanımlanırsa, Visual Basic derleyicisi "Uzantı yöntemleri yalnızca modüllerde tanımlanabilir" hata BC36551 oluşturur.

Uzantı yöntemi tanımındaki ilk parametre, yöntemin hangi veri türünü genişletir belirtir. yöntemi çalıştırıldığında, ilk parametre yöntemi çağıran veri türünün örneğine bağlıdır.

Extension Özniteliği yalnızca bir Visual Basic Module, Subveya Functionöğesine uygulanabilir. Bunu bir Class veya Structure öğesine uygularsanız, Visual Basic derleyicisi hata BC36550 oluşturur: "'Uzantı' özniteliği yalnızca 'Module', 'Sub' veya 'Fonksiyon' bildirimlerine uygulanabilir".

Örnek

Aşağıdaki örnek, Print veri türüne bir String uzantısı tanımlar. Yöntem, bir dizeyi görüntülemek için Console.WriteLine kullanır. Print yönteminin parametresi, aString yönteminin, String sınıfını genişlettiğini belirtir.

Imports System.Runtime.CompilerServices

Module StringExtensions

    <Extension()> 
    Public Sub Print(ByVal aString As String)
        Console.WriteLine(aString)
    End Sub

End Module

Uzantı yöntemi tanımının uzantı özniteliğiyle <Extension()>işaretlendiğini fark edin. Yöntemin tanımlandığı modülün işaretlenmesi isteğe bağlıdır, ancak her uzantı yönteminin işaretlenmesi gerekir. System.Runtime.CompilerServices uzantı özniteliğine erişmek için içeri aktarılmalıdır.

Uzantı yöntemleri yalnızca modüller içinde bildirilebilir. Genellikle, bir uzantı yönteminin tanımlandığı modül, çağrıldığı modülle aynı modül değildir. Bunun yerine, uzantı yöntemini içeren modül, ihtiyaç duyulursa kapsam içine almak için içe aktarılır. Print içeren modül kapsam dahilinde olduktan sonra, yöntem bağımsız değişken içermeyen sıradan bir örnek yöntemiymiş gibi ToUpper çağrılabilir.

Module Class1

    Sub Main()

        Dim example As String = "Hello"
        ' Call to extension method Print.
        example.Print()

        ' Call to instance method ToUpper.
        example.ToUpper()
        example.ToUpper.Print()

    End Sub

End Module

Sonraki örnek, PrintAndPunctuate, bu kez iki parametreyle tanımlanan String uzantısına bir örnektir. İlk parametre, aString, uzantı yönteminin String tarafından genişletildiğini ortaya koyar. İkinci parametre olan punc, yöntemi çağrıldığında bağımsız değişken olarak geçirilen bir noktalama işaretleri dizesi olması amaçlanmıştır. yöntemi, dizeyi ve ardından noktalama işaretlerini görüntüler.

<Extension()> 
Public Sub PrintAndPunctuate(ByVal aString As String, 
                             ByVal punc As String)
    Console.WriteLine(aString & punc)
End Sub

Bu yöntem, punc için bir dize bağımsız değişkeni göndererek çağrılır: example.PrintAndPunctuate(".")

Aşağıdaki örnek, Print ve PrintAndPunctuate'in tanımlandığını ve çağrıldığını göstermektedir. System.Runtime.CompilerServices uzantı özniteliğine erişimi etkinleştirmek için tanım modülünde içeri aktarılır.

Imports System.Runtime.CompilerServices

Module StringExtensions

    <Extension()>
    Public Sub Print(aString As String)
        Console.WriteLine(aString)
    End Sub

    <Extension()>
    Public Sub PrintAndPunctuate(aString As String, punc As String)
        Console.WriteLine(aString & punc)
    End Sub
End Module

Daha sonra uzantı yöntemleri kapsama alınır ve şu şekilde çağrılır:

Imports ConsoleApplication2.StringExtensions

Module Module1

    Sub Main()
        Dim example As String = "Example string"
        example.Print()

        example = "Hello"
        example.PrintAndPunctuate(".")
        example.PrintAndPunctuate("!!!!")
    End Sub
End Module

Bu veya benzer uzantı yöntemlerini çalıştırabilmek için gereken tek şey kapsam dahilinde olmalarıdır. Uzantı yöntemi içeren modül kapsam dahilindeyse IntelliSense'te görünür ve sıradan bir örnek yöntemiymiş gibi çağrılabilir.

Yöntemler çağrıldığında, ilk parametre için hiçbir bağımsız değişken gönderilmediğini fark edin. Önceki yöntem tanımlarındaki aString parametresi, onları çağıran example örneğine bağlı olan String ile ilişkilidir. Derleyici, example'yi ilk parametreye gönderilen bağımsız değişken olarak kullanacaktır.

olarak ayarlanmış Nothingbir nesne için bir uzantı yöntemi çağrılırsa, uzantı yöntemi yürütülür. Bu normal örnek yöntemleri için geçerli değildir. Uzantı yönteminde Nothing için açıkça kontrol edebilirsiniz.

Genişletilebilen türler

Aşağıdakiler de dahil olmak üzere Visual Basic parametre listesinde temsil edilebilen çoğu türde bir uzantı yöntemi tanımlayabilirsiniz:

  • Sınıflar (referans türleri)
  • Yapılar (değer türleri)
  • Arayüzler
  • Temsilciler
  • ByRef ve ByVal bağımsız değişkenleri
  • Genel yöntem parametreleri
  • Diziler

İlk parametre uzantı yönteminin genişletildiği veri türünü belirttiğinden gereklidir ve isteğe bağlı olamaz. Bu nedenle, Optional parametreler ve ParamArray parametreler parametre listesindeki ilk parametre olamaz.

Uzantı yöntemleri geç bağlamada dikkate alınmaz. anObject.PrintMe() ifadeleri aşağıdaki örnekte bir MissingMemberException istisnası oluşturur ki bu, ikinci PrintMe uzantı yöntemi tanımı silinirse göreceğiniz istisnadır.

Option Strict Off
Imports System.Runtime.CompilerServices

Module Module4

    Sub Main()
        Dim aString As String = "Initial value for aString"
        aString.PrintMe()

        Dim anObject As Object = "Initial value for anObject"
        ' The following statement causes a run-time error when Option
        ' Strict is off, and a compiler error when Option Strict is on.
        'anObject.PrintMe()
    End Sub

    <Extension()> 
    Public Sub PrintMe(ByVal str As String)
        Console.WriteLine(str)
    End Sub

    <Extension()> 
    Public Sub PrintMe(ByVal obj As Object)
        Console.WriteLine(obj)
    End Sub

End Module

En iyi yöntemler

Uzantı yöntemleri, mevcut bir türü genişletmek için kullanışlı ve güçlü bir yol sağlar. Ancak, bunları başarıyla kullanmak için dikkate alınması gereken bazı noktalar vardır. Bu konular temel olarak sınıf kitaplıklarının yazarları için geçerlidir, ancak uzantı yöntemlerini kullanan tüm uygulamaları etkileyebilir.

Genellikle, sahip olmadığınız türlere eklediğiniz uzantı yöntemleri, denetlediğiniz türlere eklenen uzantı yöntemlerinden daha savunmasızdır. Sahip olmadığınız sınıflarda uzantı yöntemlerinizi engelleyebilecek çeşitli şeyler oluşabilir.

  • Erişilebilir herhangi bir örnek üye, çağırma deyimindeki bağımsız değişkenlerle uyumlu bir imzaya sahipse ve bağımsız değişkenden parametreye daraltma dönüştürmesi gerekmiyorsa, örnek yöntem, herhangi bir uzantı yönteminden önce tercih edilir. Bu nedenle, bir noktada bir sınıfa uygun bir örnek yöntemi eklenirse, kullandığınız mevcut bir uzantı üyesi erişilemez hale gelebilir.

  • Bir uzantı yönteminin yazarı, diğer programcıların özgün uzantıdan öncelikli olabilecek çakışan uzantı yöntemleri yazmasını engelleyemez.

  • Uzantı yöntemlerini kendi ad alanlarına yerleştirerek sağlamlığı geliştirebilirsiniz. Daha sonra kitaplığınızın tüketicileri bir ad alanı ekleyebilir veya bu ad alanını dışlayabilir ya da kitaplığın geri kalanından ayrı olarak ad alanları arasından seçim yapabilir.

  • Arabirimleri genişletmek, özellikle de arabirimin veya sınıfın sahibi değilseniz sınıfları genişletmekten daha güvenli olabilir. Arabirimdeki bir değişiklik, bunu uygulayan her sınıfı etkiler. Bu nedenle, yazarın arabirime yöntem ekleme veya değiştirme olasılığı daha düşük olabilir. Ancak, bir sınıf aynı imzaya sahip uzantı yöntemlerine sahip iki arabirim uygularsa, her iki uzantı yöntemi de görünür olmaz.

  • Kullanabileceğiniz en özel türü genişletin. Türlerin hiyerarşisinde, başka birçok türün türetildiği bir tür seçerseniz, örnek yöntemlerinin veya diğer uzantı yöntemlerinin sizinkine müdahale etme olasılığı vardır.

Uzantı yöntemleri, örnek yöntemleri ve özellikler

Kapsam içi bir örnek metot, çağrı ifadesinin argümanlarıyla uyumlu bir imzaya sahip olduğunda, bu örnek metot herhangi bir uzantı metoduna tercih edilir. Uzantı yöntemi daha iyi bir eşleşme olsa bile örnek yönteminin önceliği vardır. Aşağıdaki örnekte, bir ExampleClass türünde parametresi olan ExampleMethod adlı bir örnek yöntemi içeren Integer yer almaktadır. Uzantı yöntemi ExampleMethodExampleClass'i genişletir ve Long türünde bir parametreye sahiptir.

Class ExampleClass
    ' Define an instance method named ExampleMethod.
    Public Sub ExampleMethod(ByVal m As Integer)
        Console.WriteLine("Instance method")
    End Sub
End Class

<Extension()> 
Sub ExampleMethod(ByVal ec As ExampleClass, 
                  ByVal n As Long)
    Console.WriteLine("Extension method")
End Sub

Aşağıdaki koddaki ilk ExampleMethod çağrısı genişletme yöntemini çağırır, çünkü arg1Long'dir ve yalnızca genişletme yöntemindeki Long parametresiyle uyumludur. ExampleMethod'a yapılan ikinci çağrı, bir Integer bağımsız değişkeni olan arg2 ile birlikte gelir ve örnek metodunu çağırır.

Sub Main()
    Dim example As New ExampleClass
    Dim arg1 As Long = 10
    Dim arg2 As Integer = 5

    ' The following statement calls the extension method.
    example.exampleMethod(arg1)
    ' The following statement calls the instance method.
    example.exampleMethod(arg2)
End Sub

Şimdi iki yöntemde parametrelerin veri türlerini tersine çevirin:

Class ExampleClass
    ' Define an instance method named ExampleMethod.
    Public Sub ExampleMethod(ByVal m As Long)
        Console.WriteLine("Instance method")
    End Sub
End Class

<Extension()> 
Sub ExampleMethod(ByVal ec As ExampleClass, 
                  ByVal n As Integer)
    Console.WriteLine("Extension method")
End Sub

Bu kez içindeki Main kod her iki kez de örnek yöntemini çağırır. Bunun nedeni, hem arg1 hem de arg2 için Long'ya genişletme dönüştürmesi olması ve her iki durumda da örnek yönteminin uzantı yönteminden öncelikli olmasıdır.

Sub Main()
    Dim example As New ExampleClass
    Dim arg1 As Long = 10
    Dim arg2 As Integer = 5

    ' The following statement calls the instance method.
    example.ExampleMethod(arg1)
    ' The following statement calls the instance method.
    example.ExampleMethod(arg2)
End Sub

Bu nedenle, bir uzantı yöntemi mevcut bir örnek yönteminin yerini alamaz. Ancak, bir uzantı yöntemi bir örnek yöntemiyle aynı ada sahipse ancak imzalar çakışmadığında, her iki yönteme de erişilebilir. Örneğin, ExampleClass sınıfı içinde, ExampleMethod adlı ve bağımsız değişken almayan bir yöntem varsa, aşağıdaki kodda gösterildiği gibi aynı ada sahip ancak farklı imzalara sahip genişletme yöntemlerine izin verilir.

Imports System.Runtime.CompilerServices

Module Module3

    Sub Main()
        Dim ex As New ExampleClass
        ' The following statement calls the extension method.
        ex.ExampleMethod("Extension method")
        ' The following statement calls the instance method.
        ex.ExampleMethod()
    End Sub

    Class ExampleClass
        ' Define an instance method named ExampleMethod.
        Public Sub ExampleMethod()
            Console.WriteLine("Instance method")
        End Sub
    End Class

    <Extension()> 
    Sub ExampleMethod(ByVal ec As ExampleClass, 
                  ByVal stringParameter As String)
        Console.WriteLine(stringParameter)
    End Sub

End Module

Bu kodun çıktısı aşağıdaki gibidir:

Extension method
Instance method

Durum özelliklerle daha basittir: Uzantı yöntemi genişletilen sınıfın özelliğiyle aynı ada sahipse, uzantı yöntemi görünür değildir ve erişilemez.

Uzantı yöntemi önceliği

Aynı imzalara sahip iki uzantı yöntemi kapsam içinde ve erişilebilir olduğunda, daha yüksek önceliğe sahip olan yöntem çağrılır. Uzantı yönteminin önceliği, yöntemi kapsama getirmek için kullanılan mekanizmayı temel alır. Aşağıdaki liste, en yüksekten en düşüğe kadar öncelik hiyerarşisini gösterir.

  1. Geçerli modülün içinde tanımlanan uzantı yöntemleri.

  2. Geçerli ad alanındaki veya herhangi bir üst ad alanındaki veri türlerinin içinde tanımlanan uzantı yöntemleri, alt ad alanlarının üst ad alanlarına göre daha yüksek önceliğe sahiptir.

  3. Geçerli dosyadaki herhangi bir tür içeri aktarma işleminde tanımlanan uzantı yöntemleri.

  4. Geçerli dosyadaki herhangi bir ad alanı içindeki uzantı yöntemleri tanımlanır.

  5. Proje düzeyindeki herhangi bir tür içeri aktarma işleminde tanımlanan uzantı yöntemleri.

  6. Proje düzeyindeki ad alanı içeri aktarma işlemlerinde tanımlanan uzantı yöntemleri.

Öncelik belirsizliği çözmezse, çağırdığınız yöntemi belirtmek için tam adı kullanabilirsiniz. Önceki örnekteki Print yöntemi, StringExtensions adlı bir modülde tanımlanmışsa, tam ad StringExtensions.Print(example) yerine example.Print() olacaktır.

Ayrıca bakınız