Visual Basic 2012 Voorbeelden
   

visual basic 2012 broncode voorbeelden

Blijf op de hoogte van de recente aanpassingen op vbvoorbeelden!

Microsoft Visual Studio 2012Microsoft Developers Network - Visual BasicMicrosoft .NET Framework

11.5. Shadowing - Shadows

Print Email Deel op Twitter Deel op Facebook

Dit artikel is gepubliceerd op maandag 15 oktober 2012 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.

11.5.1. Redefinition - Overridable en Overrides

De compiler zal beslissen op basis van het statisch type van de ontvangerexpressie welke member wordt aangeroepen.
At runtime bepaalt het dynamisch type van de ontvangerexpressie aan welke implementatie deze call gebonden wordt.
Visual Basic 2012 Broncode - Codevoorbeeld 312
Namespace Redefinition
    Class Class1
        Public Overridable Sub Method1()
            Console.WriteLine("Class1.Method1()")
        End Sub
    End Class
    Class Class2 : Inherits Class1
        Public Overrides Sub Method1()
            Console.WriteLine("Class2.Method1()")
        End Sub
    End Class
    Class Class3 : Inherits Class2
        Public Overrides Sub Method1()
            Console.WriteLine("Class3.Method1()")
        End Sub
    End Class
    Class Example
        Public Shared Sub Main()
            Dim object1_1 As Class1 = New Class1
            Dim object1_2 As Class1 = New Class2
            Dim object1_3 As Class1 = New Class3
            Dim object2_2 As Class2 = New Class2
            Dim object2_3 As Class2 = New Class3
            Dim object3_3 As Class3 = New Class3
            '
            object1_1.Method1()
            object1_2.Method1()
            object1_3.Method1()
            object2_2.Method1()
            object2_3.Method1()
            object3_3.Method1()
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
Class1.Method1()
Class2.Method1()
Class3.Method1()
Class2.Method1()
Class3.Method1()
Class3.Method1()

11.5.2. Shadowing - Shadows

Iets wat vaak verward wordt met redefinition is "shadowing", toch heeft dit een totaal ander effect.

De overschaduwende member (hier Method1 uit Class2), die wordt gemarkeerd met het Shadows keyword, is een nieuwe member die wordt toegevoegd in een afgeleide klasse, hier toegevoegd in Class2.
Deze nieuwe member heeft dezelfde naam als de overschaduwde member.

Door shadowing toe te passen worden verdere herdefinities van de overschaduwde member (hier Method1 uit Class1) - vanaf de klasse die deze overschaduwende member introduceert (Class2) - verhinderd.
Visual Basic 2012 Broncode - Codevoorbeeld 313
Namespace Shadowing
    Class Class1
        Public Overridable Sub Method1()
            Console.WriteLine("Class1.Method1()")                          ' (1)
        End Sub
    End Class
    Class Class2 : Inherits Class1
        Public Overridable Shadows Sub Method1()
            Console.WriteLine("Class2.Method1()")                          ' (2)
        End Sub
    End Class
    Class Class3 : Inherits Class2
        Public Overrides Sub Method1()
            Console.WriteLine("Class3.Method1()")                          ' (3)
        End Sub
    End Class
End Namespace
Er is hier sprake van twee verschillende members met de naam Method1.

De eerste gedefinieerd in Class1 bevat implementatie (1) en wordt overgeërfd in Class2 en Class3.
Types Class2 en Class3 erven dan ook implementatie (1) over.

De tweede Method1 is gedefinieerd vanaf Class2 en bevat implementatie (2), deze wordt overgeërfd en geherdefinieerd in Class3 met implementatie (3).
Een nieuwe member wordt in Class2 geïntroduceerd, deze nieuwe member heeft dezelfde naam heeft als een overgeërfde member.  Naast de gemeenschappelijke identifier hebben deze twee verschillende Method1 members niets met elkaar te maken.
Het is echter wel zo dat vanaf Class2 de eerste Method1 niet meer kan worden geherdefinieerd.

De compiler zal op basis van het statisch type van de ontvangerexpressie bepalen welke Method1 wordt aangeroepen.  Hiervoor verkiest hij de meest recent gedefinieerde Method1.

Op ontvangerexpressie van statisch type Class1 kan men slechts één Method1 (de eerste) worden aangeroepen.
Wanneer Method1 op ontvangerexpressies van statisch types Class2 of Class3 wordt aangeroepen dan beschouwd de compiler dit als een call naar de tweede Method1.
Visual Basic 2012 Broncode - Codevoorbeeld 314
Namespace Shadowing
    Class Example
        Public Shared Sub Main()
            Dim object1_1 As Class1 = New Class1
            Dim object1_2 As Class1 = New Class2
            Dim object1_3 As Class1 = New Class3
            Dim object2_2 As Class2 = New Class2
            Dim object2_3 As Class2 = New Class3
            Dim object3_3 As Class3 = New Class3
            '
            object1_1.Method1()
            object1_2.Method1()
            object1_3.Method1()
            object2_2.Method1()
            object2_3.Method1()
            object3_3.Method1()
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
Class1.Method1()
Class1.Method1()
Class1.Method1()
Class2.Method1()
Class3.Method1()
Class3.Method1()
De regels omtrent shadowing zijn ingewikkeld en vaak verschillend.
De verschillende talen gebruiken verschillende variaties van shadowing, naast "shadowing by name" beschikken sommige talen ook over de mogelijkheid om "shadowing by signature" toe te passen.
Dit in tegenstelling tot bijvoorbeeld overloading of redefinition.  In bijna alle talen zijn de regels omtrent deze gelijk, dit is niet het geval bij shadowing.

In Visual Basic is zowel shadowing by name als by signature mogelijk.

Het gebruik van shadowing veroorzaakt moeilijk leesbare code, hierdoor raadt men doorgaans aan enkel shadowing te gebruiken indien noodzakelijk.

11.5.3. Fragile Base Class Problem

Indien een basisklasse - waarvan je niet de eigenaar bent - opeens een member introduceert met dezelfde identifier als een member uit je eigen gespecialiseerde klasse, kan het nuttig zijn shadowing toe te passen.
Wat voor effect bovenstaande situatie zou hebben, is afhankelijk van de gebruikte taal.  Sommige talen zouden fouten geven, ander talen zouden je eigen member (uit de gespecialiseerde klasse) als een overschrijvende member beschouwen.  Indien er echter geen verband is tussen de member uit de basis- en afgeleide klasse, is shadowing meer toepasselijk dan redefinition.
Visual Basic zal in bovenvermelde situatie automatisch schadowing gebruiken.

Basisklassen zijn fragiele dingen, als je er wijzingen aan aanbrengt kan dit grote gevolgen hebben voor de afgeleiden.

Veronderstel onderstaande CharString.
Visual Basic 2012 Broncode - Codevoorbeeld 315
Namespace FragileBaseClass1
    Class CharString
        Private _Items As Char() = {}
        Public Overridable Sub Add(ByVal aChar As Char)
            ReDim Preserve _Items(_Items.Length)
            _Items(_Items.Length - 1) = aChar
        End Sub
        Public Overridable Sub AddAll(ByVal chars As Char())
            For Each charElement As Char In chars
                Add(charElement)
            Next
        End Sub
        Public Overrides Function ToString() As String
            If _Items IsNot Nothing Then
                For Each charElement As Char In _Items
                    ToString &= charElement
                Next
            End If
        End Function
    End Class
End Namespace
In de abstractie (hier in de publieke interface) van de klasse CharString is niet voorzien om in clients het aantal elementen (aantal Chars) op te vragen.
Als we deze mogelijkheid toch willen toevoegen, zonder de basisklasse aan te passen (omdat we dit niet kunnen (bijvoorbeeld niet beschikken over de sourcecode) of niet wensen), kunnen we hiervoor een afgeleide klasse creëren.
Visual Basic 2012 Broncode - Codevoorbeeld 316
Namespace FragileBaseClass1
    Class CountedCharString : Inherits CharString
        Private _Count As Integer
        Public Overrides Sub Add(ByVal aChar As Char)
            MyBase.Add(aChar)
            _Count += 1
        End Sub
        Public ReadOnly Property Count() As Integer
            Get
                Count = _Count
            End Get
        End Property
    End Class
End Namespace
Bovenstaande klasse biedt nu de gewenste mogelijkheid, om het aantal characters uit het CharString object op te vragen.
Visual Basic 2012 Broncode - Codevoorbeeld 317
Namespace FragileBaseClass1
    Class Example
        Public Shared Sub Main()
            Dim countedCharString1 As New CountedCharString
            countedCharString1.Add("a"c)
            countedCharString1.Add("b"c)
            countedCharString1.AddAll(New Char() {"c"c, "d"c})
            Console.WriteLine(countedCharString1.ToString())
            Console.WriteLine(countedCharString1.Count)
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
abcd
4
De expressie countedCharString1.Count levert 4 op.

Toch is bovenstaande geherdefinieerde implementatie van de Add method in de CountedCharString klasse een riskante onderneming.  De opgeleverde Count waarde is hier afhankelijk van het aantal keer de Add method wordt aangeroepen.  Enkel doordat de AddAll method de Add method gebruikt, functioneert dit correct.

Stel in de basisklasse wordt de minder efficiënte AddAll implementatie vervangen door een efficiënter implementatie.
Visual Basic 2012 Broncode - Codevoorbeeld 318
Namespace FragileBaseClass2
    Class CharString
        Private _Items As Char() = {}
        Public Overridable Sub Add(ByVal aChar As Char)
            ReDim Preserve _Items(_Items.Length)
            _Items(_Items.Length - 1) = aChar
        End Sub
        Public Overridable Sub AddAll(ByVal chars As Char())
            Dim oldUpperBound, newUpperBound As Integer
            If _Items IsNot Nothing Then oldUpperBound = _Items.Length - 1
            If chars IsNot Nothing Then newUpperBound = _
                                                    oldUpperBound + chars.Length
            ReDim Preserve _Items(newUpperBound)
            Dim index As Integer = oldUpperBound + 1
            For Each charElement As Char In chars
                _Items(index) = charElement
                index += 1
            Next
        End Sub
        Public Overrides Function ToString() As String
            If _Items IsNot Nothing Then
                For Each charElement As Char In _Items
                    ToString &= charElement
                Next
            End If
        End Function
    End Class
    Class CountedCharString : Inherits CharString
        Private _Count As Integer
        Public Overrides Sub Add(ByVal aChar As Char)
            MyBase.Add(aChar)
            _Count += 1
        End Sub
        Public ReadOnly Property Count() As Integer
            Get
                Count = _Count
            End Get
        End Property
    End Class
End Namespace
Dan zal dezelfde client zal voor de expressie countedCharString1.Count twee opleveren.
Visual Basic 2012 Broncode - Codevoorbeeld 319
Namespace FragileBaseClass2
    Class Example
        Public Shared Sub Main()
            Dim countedCharString1 As New CountedCharString
            countedCharString1.Add("a"c)
            countedCharString1.Add("b"c)
            countedCharString1.AddAll(New Char() {"c"c, "d"c})
            Console.WriteLine(countedCharString1.ToString())
            Console.WriteLine(countedCharString1.Count)
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
abcd
2
Wat duidelijk niet correct is.

Het probleem zou hier op te lossen zijn door ook de AddAll method in de afgeleide klasse te herdefiniëren.

11.5.4. Overloading, Redefinition of Shadowing

Stel dat zowel Class1 als Class2 (die overerft van Class1) een member met de signatuur Public Sub Test() definiëren.
Visual Basic 2012 Broncode - Codevoorbeeld 320
Namespace OverloadingRedefinitionOrShadowing1
    Class Class1
        Public Sub Test()
            Console.WriteLine("Class1.Test()")
        End Sub
    End Class
    Class Class2 : Inherits Class1
        Public Sub Test()
            Console.WriteLine("Class2.Test()")
        End Sub
    End Class
    Class Example
        Public Shared Sub Main()
            Dim object1_1 As Class1 = New Class1
            object1_1.Test()
            Dim object1_2 As Class1 = New Class2
            object1_2.Test()
            Dim object2 As Class2 = New Class2
            object2.Test()
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
Class1.Test()
Class1.Test()
Class2.Test()
Dan zie je hoe shadowing wordt toegepast, ondanks dat we dit niet expliciet hebben opgegeven (geen gebruik van het keyword Shadows).

De compiler geeft wel een warning dat shadowing zal worden gebruikt.

Stel dat Class1 een Public Overridable Sub Test() definieert en afgeleide Class2 hier een Public Sub Test() aan toevoegt.
Visual Basic 2012 Broncode - Codevoorbeeld 321
Namespace OverloadingRedefinitionOrShadowing2
    Class Class1
        Public Overridable Sub Test()
            Console.WriteLine("Class1.Test()")
        End Sub
    End Class
    Class Class2 : Inherits Class1
        Public Sub Test()
            Console.WriteLine("Class2.Test()")
        End Sub
    End Class
    Class Example
        Public Shared Sub Main()
            Dim object1_1 As Class1 = New Class1
            object1_1.Test()
            Dim object1_2 As Class1 = New Class2
            object1_2.Test()
            Dim object2 As Class2 = New Class2
            object2.Test()
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
Class1.Test()
Class1.Test()
Class2.Test()
Ook hier zal shadowing worden toegepast zonder dat we dit expliciet aangeven.

We krijgen opnieuw een warning die ons waarschuwt dat shadowing zal worden toegepast.

Stel basisklasse Class1 met een Public Overridable Sub Test() waarvan afgeleide klasse een Public Overrides Sub Test() toevoegt.
Visual Basic 2012 Broncode - Codevoorbeeld 322
Namespace OverloadingRedefinitionOrShadowing3
    Class Class1
        Public Overridable Sub Test()
            Console.WriteLine("Class1.Test()")
        End Sub
    End Class
    Class Class2 : Inherits Class1
        Public Overrides Sub Test()
            Console.WriteLine("Class2.Test()")
        End Sub
    End Class
    Class Example10
        Public Shared Sub Main()
            Dim object1_1 As Class1 = New Class1
            object1_1.Test()
            Dim object1_2 As Class1 = New Class2
            object1_2.Test()
            Dim object2 As Class2 = New Class2
            object2.Test()
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
Class1.Test()
Class2.Test()
Class2.Test()
Bovenstaand voorbeeld maakt op correcte wijze gebruik van redefinition.

Stel klasse Class1 met Public Sub Test() en een afgeleide klasse Class2 met een Public Shadows Sub Test().
Visual Basic 2012 Broncode - Codevoorbeeld 323
Namespace OverloadingRedefinitionOrShadowing4
    Class Class1
        Public Sub Test()
            Console.WriteLine("Class1.Test()")
        End Sub
    End Class
    Class Class2 : Inherits Class1
        Public Shadows Sub Test()
            Console.WriteLine("Class2.Test()")
        End Sub
    End Class
    Class Example11
        Public Shared Sub Main()
            Dim object1_1 As Class1 = New Class1
            object1_1.Test()
            Dim object1_2 As Class1 = New Class2
            object1_2.Test()
            Dim object2 As Class2 = New Class2
            object2.Test()
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
Class1.Test()
Class1.Test()
Class2.Test()
Bovenstaand voorbeeld maakt op gebruik van shadowing, hier wordt dit ook expliciet aangegeven via het keyword Shadows.

Stel klasse Class1 met Public Sub Test() en afgeleide klasse Class2 met een Public Overloads Sub Test().
Visual Basic 2012 Broncode - Codevoorbeeld 324
Namespace OverloadingRedefinitionOrShadowing5
    Class Class1
        Public Sub Test()
            Console.WriteLine("Class1.Test()")
        End Sub
    End Class
    Class Class2 : Inherits Class1
        Public Overloads Sub Test()
            Console.WriteLine("Class2.Test()")
        End Sub
    End Class
    Class Example12
        Public Shared Sub Main()
            Dim object1_1 As Class1 = New Class1
            object1_1.Test()
            Dim object1_2 As Class1 = New Class2
            object1_2.Test()
            Dim object2 As Class2 = New Class2
            object2.Test()
            '
            Console.ReadLine()
        End Sub
    End Class
End Namespace
Console Application Output
Class1.Test()
Class1.Test()
Class2.Test()
In klasse Class2 wordt gesuggereerd dat overloading wordt gebruikt, maar er zijn geen verschillen aangebracht in de parameters (wat vereist is volgens de overload resolution).  Dit is een foutieve toepassing van overloading.

Hier zal shadowing worden gebruikt, ondanks het keyword Overloads, bemerk dat de compiler ons hier geen waarschuwing voor geeft.

Dit artikel is gepubliceerd op maandag 15 oktober 2012 op vbvoorbeelden, bezoek de website voor een recente versie van dit artikel of andere artikels.