Metody rozšíření (Visual Basic)
Rozšiřující metody umožňují vývojářům přidat vlastní funkce k datovým typům, které jsou již definovány, bez vytváření nového odvozeného typu.Rozšiřující metody umožňují napsat metodu, která může být volána, jako by šlo o metodu instance existujícího typu.
Poznámky
Metoda rozšíření může být pouze procedura Sub nebo Function.Nelze definovat vlastnost rozšíření, pole nebo události.Všechny metody rozšíření musí být označeny pomocí atributu rozšíření <Extension()> z oboru názvů System.Runtime.CompilerServices.
První parametr v metodě rozšíření určuje, jaký typ dat metoda rozšiřuje.Při spuštění metody je první parametr vázán na datový typ, který vyvolá metodu instance.
Příklad
Description
Následující příklad definuje rozšíření Print pro datový typ String.Metoda používá Console.WriteLine pro zobrazení řetězce.Parametr metody Print, aString, stanoví, že metody rozšíří třídu String.
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension()>
Public Sub Print(ByVal aString As String)
Console.WriteLine(aString)
End Sub
End Module
Všimněte si, že definice metody rozšíření je označena atributem rozšíření <Extension()>.Označení modulu, ve kterém je definována metoda, je nepovinné, ale každá rozšiřující metoda musí být označena.System.Runtime.CompilerServices musí být importovány, pokud chcete získat přístup k atributu rozšíření.
Metody rozšíření lze deklarovat jen v modulech.Modul, ve kterém je definována rozšiřující metoda, obvykle není stejný modul jako ten, ve kterém je volán.Namísto toho se importuje modul, který obsahuje metodu rozšíření importu (pokud je nutné, pro přivedení do rozsahu).Jakmile bude modul obsahující Print v oboru, lze volat metodu, jako by šlo o běžnou metodu instance, která nepřijímá žádné argumenty, jako například ToUpper:
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
V dalším příkladu PrintAndPunctuate je také rozšíření String, tentokrát definováno se dvěma parametry.První parametr aString stanoví, že metoda rozšíření rozšiřuje parametr String.Druhý parametr punc je určen jako řetězec interpunkčního znaménka, které je předáno jako argument při volání metody.Metoda zobrazí řetězec následovaný interpunkčními znaménky.
<Extension()>
Public Sub PrintAndPunctuate(ByVal aString As String,
ByVal punc As String)
Console.WriteLine(aString & punc)
End Sub
Je volána metoda odesláním v argumentu řetězce pro punc: example.PrintAndPunctuate(".")
Následující příklad ukazuje definované a volané výrazy Print a PrintAndPunctuate.System.Runtime.CompilerServices importován v modulu definice s cílem umožnit přístup k atributu rozšíření.
Kód
Imports System.Runtime.CompilerServices
Module StringExtensions
<Extension()>
Public Sub Print(ByVal aString As String)
Console.WriteLine(aString)
End Sub
<Extension()>
Public Sub PrintAndPunctuate(ByVal aString As String,
ByVal punc As String)
Console.WriteLine(aString & punc)
End Sub
End Module
Dále se rozšiřující metody uvedou do rozsahu a budou volány.
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
Komentáře
Ke spouštění těchto nebo podobných metod rozšíření stačí, aby byly v oboru.Pokud je modul, který obsahuje rozšiřující metodu v oboru, je zobrazen v technologii IntelliSense a může být volán, jako by šlo o běžnou metodu instance.
Všimněte si, že když jsou metody vyvolány, žádný argument se pro první parametr neodešle.Parametr aString v předchozí definici metody je vázán na example, instanci String, která je volá.Kompilátor použije example jako argument odeslaný na první parametr.
Pokud se volá metoda rozšíření pro objekt, který je nastaven na Nothing, metoda rozšíření se zavolá.To se nevztahuje na běžné metody instancí.Můžete explicitně zjišťovat Nothing v rozšířené metodě.
Typy, které lze rozšířit
Můžete definovat rozšiřující metodu pro většinu typů, které mohou být zastoupeny v seznamu parametrů jazyka Visual Basic, včetně následujících:
Třídy (typy odkazů)
Struktury (typy hodnot)
Rozhraní
Delegáti
Argumenty ByRef a ByVal
Obecné parametry metody
Pole
Vzhledem k tomu, že první parametr určuje datový typ, který rozšiřující metoda rozšiřuje, je vyžadován a nemůže být nepovinný.Z tohoto důvodu Optional parametry a ParamArray parametry nemohou být první parametr v seznamu parametrů.
Rozšiřující metody nejsou brány v úvahu v pozdní vazbě.V následujícím příkladu vyvolává výraz anObject.PrintMe() stejnou výjimku MissingMemberException, kterou byste viděli, kdybyste odstranili druhou definici metody rozšíření PrintMe.
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
Doporučené postupy
Rozšiřující metody poskytují pohodlný a účinný způsob, jak rozšířit existující typ.Chcete-li je však úspěšně používat, existují některé body, které je třeba zvážit.Tyto úvahy platí hlavně pro autory knihoven tříd, ale mohou ovlivnit jakékoli aplikace, které používají rozšiřující metody.
Obecně jsou zranitelnější metody rozšíření přidané do typů, které nevlastníte, než metody rozšíření přidané do typů, které řídíte.Ve třídách, které nevlastníte, může dojít k řadě událostí, které mohou narušit vaše metody rozšíření.
Pokud existuje kterýkoli přístupný instanční člen, která má podpis, který je kompatibilní s argumenty v příkazu volání, bez zužujících převodů požadovaných argumentem pro parametr, bude použita instanční metoda před jakoukoli metodou rozšíření.Proto pokud metoda příslušné instance je přidána do třídy v určitém okamžiku, existující člen rozšíření, na kterého spoléháte, může být nepřístupný.
Autor metody rozšíření nemůže ostatním programátorům zabránit ve vytváření konfliktních metod rozšíření, které mohou mít přednost před původním rozšířením.
Můžete zlepšit odolnost vložením rozšiřujících metod ve vlastním oboru názvů.Spotřebitelé knihovny pak mohou zahrnout nebo vyloučit obor názvů, nebo volit mezi obory názvů odděleně od zbytku knihovny.
Více než rozšířit třídy může být bezpečnější rozšířit rozhraní, zejména v případě, že rozhraní nebo třídu nevlastníte.Změna v rozhraní se týká každé třídy, která jej implementuje.Je tedy nepravděpodobné, že autor bude chtít přidat nebo změnit metody v rozhraní.Pokud třída implementuje dvě rozhraní, která mají stejnou signaturu metody rozšíření, žádná rozšiřující metoda není nicméně viditelná.
Rozšiřte co nejspecifičtější typ.Pokud v hierarchii typů vyberete typ, z něhož je odvozeno mnoho jiných typů, existují vrstvy možností pro zavedení metody instance nebo jiných rozšiřujících metod, které by mohou narušovat vaše metody.
Rozšiřující metody, metody instance a vlastnosti
Pokud má metoda instance instance v oboru podpis, který je kompatibilní s argumenty volání příkazu, metoda instance bude zvolena v preferenci pro libovolné metody rozšíření.Instanční metoda má přednost, i když rozšiřující metoda představuje lepší shodu.V následujícím příkladu obsahuje výraz ExampleClass metodu instance pojmenovanou ExampleMethod, která má jeden parametr typu Integer.Rozšiřující metoda ExampleMethod rozšiřuje ExampleClass a má jeden parametr typu Long.
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
První volání funkce ExampleMethod v následujícím kódu volá metodu rozšíření, protože arg1 je Long a je kompatibilní pouze s parametrem Long v metodě rozšíření.Druhé volání pro ExampleMethod má argument Integer, arg2, a volá metodu instance.
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
Nyní obraťte datové typy parametrů ve dvou metodách:
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
Tentokrát kód v Main volá metodu instance obou časů.Důvodem je, že arg1 i arg2 mají rozšiřující převod na Long a metoda instance přechází v obou případech rozšiřující metodě.
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
Proto rozšiřující metoda nemůže nahradit stávající metodu instance.Pokud však rozšiřující metoda má stejný název jako metoda instance, ale podpisy nejsou v rozporu, obě metody jsou přístupné.Například pokud třída ExampleClass obsahuje metodu s názvem ExampleMethod která nebere žádné argumenty, rozšiřující metody se stejným názvem, ale různými podpisy, jsou povoleny, jak je znázorněno v následujícím kódu.
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
Výstup tohoto kódu je následující:
Extension method
Instance method
Situace je jednodušší s vlastnostmi: pokud rozšiřující metoda má stejný název jako vlastnost třídy, kterou rozšiřuje, rozšiřující metoda není viditelná a není přístupná.
Priorita rozšiřující metody
Když dvě rozšiřující metody, které mají stejné podpisy, jsou v oboru a jsou přístupné, bude vyvolána ta, která má vyšší prioritu.Přednost metody rozšíření je založena na mechanismu použitém k uvedení metody do oboru.Následující seznam obsahuje hierarchii priority od nejvyšší po nejnižší.
Rozšiřující metody definované uvnitř aktuálního modulu.
Rozšiřující metody definované uvnitř datových typů v aktuálním oboru názvů, nebo v jednom z jeho rodičů s podřízenými obory názvů, které mají vyšší prioritu než nadřazené obory názvů.
Rozšiřující metody definované uvnitř libovolných importů typu v aktuálním souboru.
Rozšiřující metody definované uvnitř libovolných importů oboru názvu v aktuálním souboru.
Rozšiřující metody definované uvnitř libovolných importů na úrovni projektu.
Rozšiřující metody definované uvnitř libovolných importů oboru názvu na úrovni projektu.
Pokud přednost nevyřeší nejednoznačnosti, můžete určit metodu, kterou voláte, přes plně kvalifikovaný název.Pokud Print metoda v předchozím příkladu je definována v modulu s názvem StringExtensions, je plně kvalifikovaný název StringExtensions.Print(example) místo example.Print().
Viz také
Referenční dokumentace
System.Runtime.CompilerServices
Metody rozšíření (Průvodce programováním v C#)
Atributy (C# and Visual Basic)
Koncepty
Parametry a argumenty procedury (Visual Basic)