Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Metody rozšíření umožňují vývojářům přidávat vlastní funkce do datových typů, které jsou již definovány bez vytvoření nového odvozeného typu. Rozšiřující metody umožňují napsat metodu, která se dá volat, jako by se jednalo o metodu instance existujícího typu.
Poznámky
Rozšiřující metoda může být pouze procedura Sub nebo procedura Function . Nelze definovat vlastnost rozšíření, pole nebo událost. Všechny metody rozšíření musí být označené atributem <Extension> rozšíření z System.Runtime.CompilerServices oboru názvů a musí být definovány v modulu. Pokud je rozšiřující metoda definována mimo modul, kompilátor jazyka Visual Basic generuje chybu BC36551" "Rozšiřující metody lze definovat pouze v modulech".
První parametr v definici metody rozšíření určuje datový typ, který metoda rozšiřuje. Při spuštění metody je první parametr vázán na instanci datového typu, který vyvolá metodu.
Atribut Extension lze použít pouze pro jazyk Visual Basic Module, Subnebo Function. Pokud ho použijete u Class nebo u Structure, kompilátor jazyka Visual Basic vygeneruje chybu BC36550, atribut "Extension" lze použít pouze u deklarací Module, Sub nebo Function.
Příklad
Následující příklad definuje rozšíření na datový typ PrintString. Metoda používá Console.WriteLine k zobrazení řetězce. Parametr Print metody aString určuje, že metoda rozšiřuje 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 <Extension()> rozšíření. Označení modulu, ve kterém je metoda definována, je nepovinná, ale každá rozšiřující metoda musí být označena.
System.Runtime.CompilerServices musí být importován, aby bylo možné získat přístup k atributu rozšíření.
Rozšiřující metody lze deklarovat pouze v modulech. Typicky není modul, ve kterém je rozšiřující metoda definována, stejný jako modul, ve kterém je tato metoda volána. Místo toho se modul obsahující metodu rozšíření naimportuje, je-li to potřeba, aby byl zahrnut do rozsahu. Po zahrnutí modulu, který obsahuje Print, lze metodu volat, jako by šlo o běžnou metodu instance objektu, která nepřijímá žádné argumenty, 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í k String, tentokrát definované se dvěma parametry. První parametr aString určuje, že daná metoda rozšiřuje String. Druhý parametr , puncje určen jako řetězec interpunkční znaménka, která je předána jako argument při zavolání metody. Metoda zobrazí řetězec následovaný interpunkčními znaménkami.
<Extension()>
Public Sub PrintAndPunctuate(ByVal aString As String,
ByVal punc As String)
Console.WriteLine(aString & punc)
End Sub
Metoda je volána dodáním argumentu typu řetězec pro punc: example.PrintAndPunctuate(".")
Následující příklad ukazuje Print a PrintAndPunctuate definované a volané.
System.Runtime.CompilerServices se importuje v definičním modulu, aby bylo možné povolit přístup k atributu rozšíření.
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
Dále se metody rozšíření uvedou do platnosti a volají se:
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
Vše, co je potřeba ke spuštění těchto nebo podobných rozšiřujících metod, je, aby byly v dosahu. Pokud je modul, který obsahuje rozšiřující metodu, v oboru, je viditelný v IntelliSense a může být volána, jako by to byla běžná metoda instance.
Všimněte si, že při vyvolání metod není pro první parametr odeslán žádný argument. Parametr aString v předchozích definicích metody je vázán na exampleinstanci String , která je volá. Kompilátor použije example jako argument, který se odešle do prvního parametru.
Pokud je volána rozšiřující metoda pro objekt, který je nastaven na Nothing, metoda rozšíření spustí. To neplatí pro běžné instance metody. V metodě rozšíření můžete explicitně zkontrolovat Nothing.
Typy, které lze rozšířit
U většiny typů, které lze reprezentovat v seznamu parametrů jazyka Visual Basic, můžete definovat metodu rozšíření, včetně následujících:
- Třídy (odkazové typy)
- Struktury (typy hodnot)
- Rozhraní
- Delegáti
- Argumenty ByRef a ByVal
- Parametry obecné metody
- Pole
Protože první parametr určuje datový typ, který rozšiřující metoda rozšiřuje, je povinný a nemůže být volitelný. Z tohoto důvodu Optional nemohou být parametry a ParamArray parametry prvním parametrem v seznamu parametrů.
Metody rozšíření nejsou považovány za opožděné vazby. V následujícím příkladu příkaz anObject.PrintMe() vyvolá výjimku, stejnou MissingMemberException výjimku byste viděli, jestli byla odstraněna druhá PrintMe definice metody rozšíření.
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
Osvědčené postupy
Rozšiřující metody poskytují pohodlný a účinný způsob, jak rozšířit existující typ. Pokud je ale chcete úspěšně použít, je potřeba zvážit několik bodů. Tyto aspekty platí hlavně pro autory knihoven tříd, ale můžou mít vliv na libovolnou aplikaci, která používá rozšiřující metody.
Obecně platí, že metody rozšíření, které přidáváte do typů, které nevlastníte, jsou zranitelnější než metody rozšíření přidané do typů, které řídíte. Některé věci mohou nastat ve třídách, které nevlastníte, a mohou zasahovat do vašich rozšiřujících metod.
Pokud existuje některý přístupný člen instance, který má podpis, který je kompatibilní s argumenty ve volajícím příkazu, bez zužující převody vyžadované z argumentu na parametr, bude metoda instance použita v předvolbě pro jakoukoli rozšiřující metodu. Proto pokud je v určitém okamžiku do třídy přidána příslušná metoda instance, může být stávající člen rozšíření, na který spoléháte, nepřístupný.
Autor metody rozšíření nemůže zabránit ostatním programátorům v psaní konfliktních rozšiřujících metod, které mohou mít přednost před původním rozšířením.
Můžete zvýšit robustnost tím, že rozšiřující metody umístíte do vlastního oboru názvů. Příjemci vaší knihovny pak můžou zahrnout obor názvů nebo ho vyloučit nebo vybrat mezi obory názvů odděleně od zbytku knihovny.
Může být bezpečnější rozšířit rozhraní, než je rozšířit třídy, zejména pokud nevlastníte rozhraní nebo třídu. Změna v rozhraní má vliv na každou třídu, která ji implementuje. Proto může být autor méně ochotný přidávat nebo měnit metody v rozhraní. Pokud však třída implementuje dvě rozhraní, která mají rozšiřující metody se stejným podpisem, není žádná metoda rozšíření viditelná.
Rozšiřte nejtypičtější typ, který můžete použít. Pokud v hierarchii typů vyberete typ, ze kterého je odvozeno mnoho dalších typů, existují vrstvy možností zavedení metod instancí nebo jiných rozšiřujících metod, které by mohly ovlivnit vaše.
Rozšiřující metody, metody instance a vlastnosti
Pokud má instanční metoda v rozsahu podpis, který je kompatibilní s argumenty volajícího příkazu, je instanční metoda zvolena v preferenci před jakoukoli metodou rozšíření. Metoda instance má přednost i v případě, že je metoda rozšíření vhodnější. V následujícím příkladu ExampleClass obsahuje metodu instance s názvem ExampleMethod jeden parametr typu Integer. Rozšiřující metoda ExampleMethod rozšiřuje ExampleClassa 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í 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í ExampleMethod má Integer argument arg2 a volá instanční metodu.
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í převraťte datové typy parametrů v těchto 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á instanční metodu dvakrát. Důvodem je to, že jak arg1 tak arg2 mají rozšiřující konverzi na Long, a instanční metoda má přednost před rozšiřující metodou v obou případech.
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 metoda rozšíření nemůže nahradit existující metodu instance. Pokud má však metoda rozšíření stejný název jako metoda instance, ale podpisy nejsou v konfliktu, lze získat přístup k oběma metodám. Pokud například třída ExampleClass obsahuje metodu s názvem ExampleMethod , která nepřijímá žádné argumenty, rozšiřující metody se stejným názvem, ale různé 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 z tohoto kódu je následující:
Extension method
Instance method
Situace je jednodušší s vlastnostmi: pokud má metoda rozšíření stejný název jako vlastnost třídy, která rozšiřuje, rozšiřující metoda není viditelná a nelze k ní získat přístup.
Priorita metody rozšíření
Pokud jsou na dosah dvě metody rozšíření, které mají identické podpisy, bude vyvolána ta s vyšší prioritou. Priorita metody rozšíření je založena na mechanismu použitém k přenesení metody do oboru. Následující seznam zobrazuje hierarchii priorit od nejvyššího po nejnižší.
Rozšiřující metody definované uvnitř aktuálního modulu.
Metody rozšíření definované uvnitř datových typů v aktuálním oboru názvů nebo některém z nadřazených oborů názvů, přičemž podřízené obory názvů mají vyšší prioritu než nadřazené obory názvů.
Rozšiřující metody definované uvnitř jakéhokoli typu importu v aktuálním souboru.
Rozšiřující metody definované uvnitř jakéhokoli importu oboru názvů v aktuálním souboru.
Rozšiřující metody definované v importech typů na úrovni projektu.
Rozšiřující metody definované v rámci importu oboru názvů na úrovni projektu.
Pokud priorita nepřeloží nejednoznačnost, můžete pomocí plně kvalifikovaného názvu zadat metodu, kterou voláte.
Print Pokud je metoda v předchozím příkladu definována v modulu s názvem StringExtensions, plně kvalifikovaný název je StringExtensions.Print(example) místo example.Print().