|
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
Types kunnen voortaan ook uitgebreid worden met extra methods ( Subs of Functions ) zonder dat hiervoor een afgeleide klasse wordt gecreëerd.
Zowel klassen, structures, delegates als interfaces zijn uitbreidbaar.
Deze extra methods worden "extension methods" genoemd.
Extension methods kunnen enkel in een module worden gedefinieerd. Deze methods worden gemarkeerd met het System.Runtime.CompilerServices.Extension attribuut.
De eerste parameter van de extension method is van het type dat wordt uitgebreid. Bij een call naar deze instancemethod wordt geen argumentwaarde voorzien voor deze eerste parameter. De implementatie voorzien in de extension wordt uitgevoerd op de doorgespeelde instantie. Visual Basic 2010 Broncode Public Module PersonExtension <System.Runtime.CompilerServices.Extension()> _ Public Sub Print( ByVal aPerson As Person) If aPerson IsNot Nothing Then Console.WriteLine( "Istance of Person : " & aPerson.ToString()) Else Console.WriteLine( "No instance of Person.") End If End SubEnd ModulePublic Class Person Private m_Name As String Public Property Name() As String Get Name = m_Name End Get Set( ByVal value As String) m_Name = value End Set End Property Public Overrides Function ToString() As String ToString = Name End FunctionEnd ClassPublic Class Student : Inherits Person Private m_ClassGroup As String Public Property ClassGroup() As String Get ClassGroup = m_ClassGroup End Get Set( ByVal value As String) m_ClassGroup = value End Set End Property Public Overrides Function ToString() As String ToString = Name & " (" & ClassGroup & ")" End FunctionEnd ClassPublic Class Example1 Public Shared Sub Main() Dim person1 As Person = New Person With {.Name = "John"} Dim person2 As Person = New Student _ With {.Name = "Jane", _ .ClassGroup = "Visual Basic"} Dim person3 As Person person1.Print() person2.Print() person3.Print() Console.ReadLine() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output Istance of Person : John
Istance of Person : Jane (Visual Basic)
No instance of Person. Overige parameters zijn mogelijk, en fungeren dan als normale parameter voor deze method.
Onderstaande CounterExtension bevat een extension method ToString met twee parameters (1). De tweede parameters is de te gebruiken paddingLength bij het omzetten naar een String. De call naar deze method (3) hoeft hier enkel voor deze parameter een waarde te voorzien.
Het type Counter wordt in onderstaand voorbeeld uitgebreid met een drietal extension methods. ToInt32 maakt het mogelijk de Counter naar een Integer om te zetten, en de twee ToString zetten om naar het String type. Visual Basic 2010 Broncode Public Class Counter Private m_Value As Integer Public ReadOnly Property Value() As Integer Get Value = m_Value End Get End Property Public Sub Raise() m_Value += 1 End Sub Public Sub Lower() m_Value -= 1 End Sub Public Overrides Function ToString() As String ToString = "Counter.Value : " & Value.ToString() End FunctionEnd ClassPublic Module CounterExtension <System.Runtime.CompilerServices.Extension()> _ Public Function ToInt32( ByVal aCounter As Counter) As Integer ToInt32 = aCounter.Value End Function <System.Runtime.CompilerServices.Extension()> _ Public Function ToString( ByVal aCounter As Counter) As String ToString = aCounter.Value.ToString() End Function <System.Runtime.CompilerServices.Extension()> _ Public Function ToString( ByVal aCounter As Counter, _ ByVal paddingLength As Integer) As String ToString = aCounter.Value.ToString().PadLeft(paddingLength) End FunctionEnd ModulePublic Class Example2 Public Shared Sub Main() Dim counter1 As New Counter counter1.Raise() counter1.Raise() Dim integerValue1 As Integer = counter1.ToInt32() Console.WriteLine(integerValue1) Dim stringValue1 As String = counter1.ToString() Console.WriteLine(stringValue1) Dim stringValue2 As String = counter1.ToString(3) Console.WriteLine(stringValue2) Console.ReadLine() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output 2
Counter.Value : 2
2 33.2.1. Extension Method PrecedenceBemerk hoe in bovenstaand voorbeeld de call op regel (2) niet de extension method, maar de gewone instancemethod ToString aanroept. De extension ToString is hier eenvoudigweg niet bereikbaar omdat reeds een gewone ToString bestaat.
Het kan ook voorkomen dat verschillende extension methods ( met identieke signatuur ) ingeladen zijn. Ambiguïteit ontstaat bij een call naar dergelijke method(s). Hier zal steeds de "dichtstbij-zijnde" method voorrang krijgen.
Zo zullen bijvoorbeeld extension methods uit namespace imports van het huidige broncode-document hogere prioriteit hebben dan extension methods uit namespace imports op project-niveau. boven
33.2.2. Extension Methods in InterfacesOok interfacetypes kunnen extension methods worden toegevoegd. Visual Basic 2010 Broncode Public Interface SomeInterface Sub SomeFirstMethod() End InterfacePublic Module SomeInterfaceExtension <System.Runtime.CompilerServices.Extension()> _ Public Sub SomeSecondMethod( ByVal aSomeInterface As SomeInterface) Console.WriteLine( "SomeInterface.SomeSecondMethod() implementation.") End SubEnd ModulePublic Class SomeClass : Implements SomeInterface Public Sub SomeFirstMethod() Implements SomeInterface. SomeFirstMethod Console.WriteLine( "SomeClass.SomeFirstMethod() implementation.") End SubEnd ClassPublic Class Example3 Public Shared Sub Main() Dim object1 As New SomeClass object1.SomeFirstMethod() object1.SomeSecondMethod() Console.ReadLine() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output SomeClass.SomeFirstMethod() implementation.
SomeInterface.SomeSecondMethod() implementation. Interface bevatten normaal gezien enkel abstracte members, die niet beschikken over een bepaalde implementatie. Het is immers niet de bedoeling in een interface te definiëren welke implemenatie wordt uitgevoerd indien deze member wordt aangeroepen.
Toch kan men interfaces enkel uitbreiden met concrete methods, die wel een implementatie bevatten. Deze extension methods worden in een modules gedefinieerd, die enkel concrete methods kunnen bevatten. boven
33.2.3. Multiple Inheritance via Interfaces en Extension MethodsAls SomeInterfaceExtension ( uit bovenstaand voorbeeld ) ingeladen is, zal elke klasse die SomeInterface implementeert nu ook over SomeSecondMethod en bijhorende implementatie beschikken.
Dit is op zijn minst wat vreemd te noemen, gezien het implementeren van interface tot nu toe enkel een vorm van "contextual inheritance" inhield. Vanaf heden is dit dus ook "implementation inheritance" mogelijk via het implementeren van een interface.
Gezien men meerdere interface kan implementeren, zouden liefhebbers van "multiple implementation inheritance" dit ook zo kunnen forceren. Visual Basic 2010 Broncode Public Interface Interface1End InterfacePublic Interface Interface2End InterfacePublic Module InterfaceExtensions <System.Runtime.CompilerServices.Extension()> _ Public Sub Method1( ByVal aInterface1 As Interface1) Console.WriteLine( "Interface1.Method1") End Sub <System.Runtime.CompilerServices.Extension()> _ Public Sub Method2( ByVal aInterface2 As Interface2) Console.WriteLine( "Interface2.Method2") End SubEnd ModulePublic Class Class1 : Implements Interface1, Interface2 End ClassPublic Class Example4 Public Shared Sub Main() Dim object1 As New Class1 object1.Method1() object1.Method2() Console.ReadLine() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Console Application Output Interface1.Method1
Interface2.Method2 boven
33.2.4. Wanneer Extension Methods GebruikenExtension methods zijn in hoofdzaak nuttig voor het uitbreiden van types waarvan je niet de eigenaar bent, of dus niet over de sourcecode beschikt.
Indien de klasse niet sealed/final ( NotInheritable ) is, dien je natuurlijk te overwegen of inheritance niet meer van toepassing is.
Extension methods gebruik je enkel indien je in een bepaalde context ( bijvoorbeeld deze van een console applicatie ) een bepaalde extra functionaliteit/gedrag nodig hebt ( bijvoorbeeld het printen op de console ), en deze functionaliteit in andere contexten niet bruikbaar/mogelijk is. Een windows applicatie bijvoorbeeld kan niets aan met een implementatie als Console.WriteLine(...).
Hoewel een extension method geschikt is voor het toevoegen van een instancemethod, kan je in de implementatie van deze slechts gebruik maken van de members uit de publieke interface van dat uit-te-breiden type. De mogelijkheden in deze implementatie zijn dus beperkt, ingekapselde members kunnen immers niet benaderd worden.
Doorgaans zal een extension method in een child namespace van de klassenbibliotheek worden ondergebracht, zodoende de client van deze library de mogelijkheid te laten deze child namespace ( met de extensions ) al dan niet in te laden.
Bijvoorbeeld de AdministrationClassLibrary zou rechtstreeks in de namespace Administration de klasse Person kunnen definiëren. Visual Basic 2010 Broncode Namespace Administration Public Class Person Private m_Name As String Public Property Name() As String Get Name = m_Name End Get Set( ByVal value As String) m_Name = value End Set End Property Public Overrides Function ToString() As String ToString = Name End Function End ClassEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Naast deze klasse kan in een child namespace ConsoleExtensions de PersonExtension worden gedefinieerd. Visual Basic 2010 Broncode Namespace Administration Namespace ConsoleExtensions Public Module PersonExtension <System.Runtime.CompilerServices.Extension()> _ Public Sub Print( ByVal aPerson As Person) System. Console.WriteLine(aPerson.ToString()) End Sub End Module End NamespaceEnd NamespaceDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
In een andere assembly als AdministrationConsoleApplication kan vervolgens beslist worden om de namespace Administration.ConsoleExtensions te importeren om de extensions beschikbaar te maken (1). Visual Basic 2010 Broncode Imports Administration.ConsoleExtensions Public Class Application Public Shared Sub Main() Dim person1 As New Administration. Person With {.Name = "John"} Console.ReadLine() End SubEnd ClassDownload Visual Basic 2010 Broncode Download Visual C# Sourcecode
Een windows applicatie zou deze extensions niet inladen, want deze zouden in die context niet bruikbaar zijn.
Dit artikel is gepubliceerd op zondag 31 juli 2011 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.
|