830 likes | 947 Views
Moderne Visual Basic-Programmierung. Peter Monadjemi (BASIC- und VB-Fan der „ ersten“ Stunde). Bei Fragen rund um VB: pm@activetraining.de. Die Themen. Kurzer Rückblick Auf dem Weg zur funktionalen Programmierung Die neue Datenschicht: EF 4.1 (Kurzer Ausflug zu WPF + MVVM)
E N D
Moderne Visual Basic-Programmierung Peter Monadjemi (BASIC- und VB-Fan der „ersten“ Stunde) Bei Fragen rund um VB: pm@activetraining.de
Die Themen • Kurzer Rückblick • Auf dem Weg zur funktionalen Programmierung • Die neue Datenschicht: EF 4.1 • (Kurzer Ausflug zu WPF + MVVM) • Neuerungen bei VB 11: Asynchrone Aufrufe und Iteratoren • Ausblick
Me.About(function(p) p.BasicJahre >30) • Beschäftige mich mit dem Thema „Programmierung“ seit ca. 1975 (zufällig das Jahr, in dem Microsoft gegründet wurde) • Meine ersten BASIC-Programme entstanden auf einem 8080 • Meine erste Programmiersprache nach BASIC war FORTH (besitzt heute immer noch eine fanatische Anhängerschaft) • Später der übliche Werdegang (C64, ST 512, ComodorePC 10 usw.) • Wohne in Esslingen (am Neckar) 10: Print "Hallo, Welt“20: GoTo 10
Meine Anfänge als Buchautor • Das Trainingsbuch zu Forth (1983) • Maschinenspracheprogrammierung (1986) • Das Visual Basic Kompendium 1.0 (1992) • Weitere VB-Bücher, Windows-Bücher usw. • Mein letztes Werk: Office 2010 mit Visual Studio • Das Visual Basic 2010 Kompendium steht noch aus
Ein kurzer Blick zurück (1) • Visual Basic 1.0 (1991) • Windows-Programmierung für Jedermann • Visual Basic 3.0 (1994) • Datenbankprogrammierung mit der Jet-Engine und dem Datensteuerelement • Visual Basic 4.0 (1996) • Der Umstieg auf 32 Bit
Ein kurzer Blick zurück (2) • Visual Basic 5.0 (1997) • Maschinencode statt P-Code • Visual Basic 6.0 (1998) • Alles Wichtige stand zur Verfügung (aber auch ein paar überflüssige Dinge, wie ActiveX Documents) • Mit .NET kam der große Bruch • Visual Basic wurde als Sprache komplett neu entwickelt und in Visual Studio integriert • Übrig blieb: Microsoft.VisualBasic.dll
Auch unter .NET gab es eine Entwicklung • Visual Studio .NET 2002/2003 waren noch sehr rudimentär • Mit Visual Studio 2005 kamen wichtige Verbesserungen speziell für die VB-Community: • >Der My-Namespace • >Windows Forms-Datenbindung • >Änderungen während einer Programmunterbrechung • >Der Aktualisierungsassistent wurde leicht verbessert • usw. • Mit Visual Studio 2008 SP1 kamen ASP.NET MVC und das Entity Framework • Mit Visual Studio 2010 kommt u.a. ein halbwegs brauchbarer WPF-Designer
Was heißt modern? • Das Gegenteil von moderner Programmierung ist nicht altmodische Programmierung • Modern bedeutet für mich: • Die Möglichkeiten der Sprache, des .NET Frameworks (der Laufzeit) und von Visual Studio zu kennen, um sie bei Bedarf einsetzen zu können • Es ist in Ordnung Lambdas nicht zu mögen (etwa unter dem Aspekt der Lesbarkeit) • Es ist nicht in Ordnung nicht zu wissen, was ein Lambda ist und welche Möglichkeiten er bietet
Schwerpunkte bei .NET 4.0, die für Visual Basic-Entwickler wichtig sind 2 3 1 LINQ Entity Framework Lambdas 5 6 4 Task Parallel Library Asynchrone Aufrufe WPF/SilverlightMVVM
Grundlage für alles: Die Programmiersprache • Typinferenz • Automatische Properties • Collection- und Array-Initialisierer • Anonyme Typen • XML-Literale • Nullable Typen und Null-Weitergabe • Erweiterungsmethoden • usw.
Typinferenz (Version 9.0) • Der Compiler kann den Typ einer lokalen Variablen aus der Zuweisung ableiten • Praktische Abkürzung, an die man sich gewöhnen muss • Ist vor allem bei LINQ-Abfragen wichtig • Ging das nicht früher (z.B. VB2005) auch schon? Beispiel Dim Zahl = 1234 DimGebDatum = "25.10.1963" Int32 DateTimeoder String?
Automatische Properties (Version 10.0) • Properties können vereinfacht definiert werden • Es wird automatisch ein privates Feld angelegt Beispiel Property Email As String
Collection- und Arrays-Initialisierer (Version 10.0) • Eine Collection kann bei der Deklaration mit Werten belegt werden (sehr praktisch) • Auch für Arrays gibt es etwas Neues Neues Schlüsselwort Beispiel Dim Spieler = New List(Of Spieler) From { New Spieler With { .Name = "Spieler1"}, New Spieler With { .Name = "Spieler2"} } Beispiel DimZahlen = {11, 22, 33, 44} Dim Matrix = {{11,111}, {22,222}, {33,333}, {444,44}} Integer() Integer(,)
Anonyme Typen (Version 9.0) • Ein Typ, der nicht explizit definiert werden muss • Und vom Compiler einen "unaussprechlichen" Namen erhält Beispiel Dim P = New With {.Name = "Pemo", .Alter = 44 } VB$AnonymousType_0`2
XML-Literale (gibt es nicht bei C#) • XML-Code kann direkt in den Quellcode eingefügt werden XElement-Objekt Eingebetteter Ausdruck Beispiel DimHTML = <HTML> <HEAD> <TITLE>Ein kleiner Test</TITLE></HEAD><BODY> <H1>XML-Literale in VB</H1><%= From z In Enumerable.Range(1, 12)Select <LI><%= MonthName(z) %></LI> %></BODY></HTML>My.Computer.FileSystem.WriteAllText("Test.html", HTML.ToString(), False, System.Text.Encoding.Default) Process.Start("Test.html")
Null-fähige Typen und Null-Weitergabe (Version 9.0) • Auch ValueType-Variablen können keinen Wert besitzen • Praktisch im Zusammenhang mit Entity Framework • Besitzt eine Property einen Nullable-Typ lässt sich abfragen,ob sie aus dem DB-Feld einen Wert erhalten hat Beispiel Class Person Property Name As String Property Alter As Integer?End Class Dim P As New Person With {.Name="Pemo" }If P.Alter.HasValue Then False Nullable Type
Null-fähige Typen und Null-Weitergabe (Version 9.0) • Null-Werte werden weitergeben (engl. null propagation) Beispiel Dim a As Integer? = Nothing Dim b As Integer? = 123 Dim c = a + b Wird zu einem Nullable-Type (Integer?) und besitzt (als ValueType) den Wert Nothing (ansonsten 123, da der Null-Wert dann nicht weitergeben wird)
Erweiterungsmethoden (engl. extensionmethods) • Jede Klasse kann nachträglich um statische Methoden erweitert werden • Methode wird in einem Modul definiert und mit dem Extension-Attribut (System.Runtime.CompilerServices) dekoriert • Zuordnung zu einer Klasse geschieht über den Typ des 1. Methodenparameters • Praktisch, da die Aufrufsyntax konsistent bleibt
Extension-Methode-Beispiel Module StringEx <Extension()> Function FirstToUpper(ByVal s As String) As String Return Mid(s, 1, 1).ToUpper() & s.Substring(1, s.Length - 1).ToLower() End Function End Module String beginnt bei 0 String-Klasse wird erweitert Erweiterungsmethode
Weitere "Sprachneuerungen" (1) • Relaxed Delegates • Für einen Prozedur-Delegaten mit Parametern kann eine parameterlose Prozedur eingesetzt werden Beispiel Sub Button1_Click()End Sub Event-Handler für das Click-Event – die Parameter Sender und e können entfallen
Weitere "Sprachneuerungen" (2) • Covarianz und Contravarianz • Varianz – die Möglichkeit z.B. bei einer generischen Liste den Typ variieren zu können, wenn der neue Typ in einer "Ist abgeleitet"- oder "Leitet sich ab"-Beziehung zu dem Originaltyp steht • Spielt in der Praxis eher selten eine Rolle • Führt zu weniger InvalidCastExceptions
Beispiel für Covarianz Module Module1 Sub Main() Dim ListeSpezial As New List(Of Spezial) From {New Spezial, New Spezial, New Spezial} Dim ListeEinfach As IEnumerable(Of Einfach) = ListeSpezialConsole.ReadLine()End SubEnd ModuleClass EinfachEnd ClassClass Spezial : Inherits EinfachEnd Class Führt bei .NET 3.5 zu einer Exception Bei ,NET 4.0 ein Out-Interface Public Interface IEnumerable(Of Out T)
Lambdas (Schwerpunkt 1) • Lambda = Funktion- oder Prozedur ohne Funktions-/Prozedurkopf • Weiterentwicklung der anonymen Methoden von C#, die es bei VB nie gegeben hat • Der Begriff kommt von Lambda Calculus (ʎ) • Vorteile: • Mehr Flexibilität, wenn Funktionscode als Parameter eingesetzt werden soll • Funktionscode kann wie Daten behandelt werden (und z.B. einer Variablen zugewiesen werden) • Grundlage für LINQ
Lambdas (2) • Function und Sub können auch rechts vom = stehen • Ein Lambda ist vom Typ Func(Of T) • Können dort eingesetzt werden, wo ein Action(Of T)- oder Predicate(Of T) –Delegat erwartet wird • Ein • sieht etwas ungewöhnlich aus (und bringt auch keine Vorteile für die Programmierung;) Dim Msg = Sub() Msgbox ("Hallo")Msg() Anonymer Delegat
Lambdas (3) • Manches erscheint auf den ersten Blick etwas ungewöhnlich Class Person Property Name As String Property Active As BooleanEnd Class Function auf der rechten Seite Dim CheckActiveUser As Func(Of Person, Boolean) = Function(p) p.Active Delegat-Typ Dim Personen As new List(Of Person) From {...}Dim AktivePersonen1 = Personen.Where(CheckActiveUser)Dim AktivePersonen2 = Personen.Where(CheckActiveUser).ToArray() WhereListIterator-Objekt Array
DoEvents-Ersatz für WPF • In C# • Wie um alles in der Welt schreibt man das in VB? public static void DoEvents() { Application.Current.Dispatcher.Invoke( DispatcherPriority.Background, new ThreadStart(delegate { })); } Anonyme Methode in C# Sub DoEvents()Application.Current.Dispatcher.Invoke( DispatcherPriority.Background, Sub()End Sub) End Sub
Die Lösung Einfach einen passenden Delegaten definieren Delegate Sub UpdateListBox(ByVal z As Integer) DimT1 As New Task(Sub()Forn = 1 To100 ListBox1.Dispatcher.Invoke(New UpdateListBox(Sub(z) ListBox1.Items.Add(z) End Sub), n) NextEnd Sub)T1.Start() Delegat wird instanziert
LINQ (Schwerpunkt 2) • Löst das "Impedanzproblem" elegant und entwicklerfreundlich • (Datenbank-) daten können direkt im Programmcode angesprochen werden • Nicht wirklich neu (erste CTP gab es im Mai 2006!) • Seit .NET 4.0 kann jede LINQ-Abfrage auch parallel ausgeführt werden • Einfach ein AsParallel() anhängen
LINQ (1) • Ist über Sprachvereinfachungen sowohl Teil der Programmiersprache als auch des .NET Framework (ab Version 3.5) Join mit Sprachvereinfachung Dim AuftraegeKundenPLZ7 = From k In Kunden Join a In Auftraege On k.KundenNr Equals a.KundenNr Where k.PLZ.StartsWith("7") Select New With {.AuftragNr = a.AuftragNr, .PLZ = k.PLZ} Join ohne Sprachvereinfachung DimAuftraegeKundenPLZ7 = Kunden.Join(Auftraege, Function(k) k.KundenNr, Function(a) a.KundenNr, Function(k, a) New With{.AuftragNr= a.AuftragNr, .PLZ = k.PLZ}).Where(Function(a) a.PLZ.StartsWith("7")) Reguläre Collection
LINQ (2) • LINQ funktioniert mit allen Collections/Arrays • Eine LINQ-Abfrage steht nicht für das Ergebnis, sondern für die Abfrage • LazyLoading (Abfrage wird erst bei der Auswertung ausgeführt) • Ergebnis wird implizit/explizit z.B. in ein Array konvertiert • Es gibt über 40 Erweiterungsmethoden, wie z.B. Group, Count, Select, Where usw. • Stammen von den Klassen Enumerable(Of T) und Queryable(Of T)
LINQ (3) • Visual Basic bietet knapp ein Dutzend Abfragevereinfachungen • from, where, select, aggregate, distinct, group, join, orderby, take, skip, let Ein einfaches Beispiel Dim AktiveUser = From u In User Where u.IsActive Select u Collection mit User-Objekten Keine Collection, Sondern "Iterator" – Abfrage wird "verzögert" Ausgeführt Iterator liefert im Rahmen einer ForEach-Schleife bei Jedem Durchlauf das nächste Objekt Damit beginnt Jede Abfrage Projektion, die den Rückgabetyp festgelegt (optional) Abfragevereinfachung Lokale Variable bezogen auf den Ausdruck
Entity Framework (Schwerpunkt 3) • Entity Framework – der offizielle ORM von Microsoft • ORM = Objektrelationaler Mapper • Objekte können direkt in einer Datenbank gespeichert werden (Persistenz) • Der ORM kümmert sich um Details wie Vererbung, Collections, Primärschlüssel-Beziehungen und das "Mappen" auf Datenbanktabellen • EF 1.0 als Teil von .NET 3.5 SP1 • Mit .NET 4.0 ist EF funktional reichhaltig genug
Ohne EF ist alles zwar vertraut, aber etwas umständlich Abrufen der Employees-Datensätze und Mappen auf Objekte Dim Employees As New List(Of Employee)Using Cn As New SqlConnection(My.Settings.NwCn) Cn.Open() Dim Cmd As SqlCommand = Cn.CreateCommand() Cmd.CommandText = "Select EmployeeID, LastName From Employees" Dim Dr As SqlDataReader = Cmd.ExecuteReader() While Dr.Read() Dim emp As New Employee With { .ID = Dr.ReadInt32(Dr.GetOrdinal("EmployeeID")) .LastName = Dr.ReadString(Dr.GetOrdinal("LastName")) Employees.Add(emp) End While Cn.Close()End Using
Mit EF wird alles sehr einfach Abrufen der Employees-Datensätze Using NwContext As New DBContext(My.Settings.NwCn) EmployeesCol = NwContext.Employees.ToList()End Using Wäre nicht erforderlich, da DBContext bereits die Datensätze als Collection zur Verfügung stellt Neuen Datensatz anhängen Using NwContext As New DBContext(My.Settings.NwCn) Dim empNeu As New Employee empNeu.LastName = "Monadjemi" NwContext.Employees.Add(empNeu) NwContext.SaveChanges()End Using
Mit EF 4.1 gibt es Code First • Separater Download (seit Mai) • Code First – Datenbank wird direkt aus dem Klassenmodell abgeleitet • Weder ein separates Mapping noch der Entity Designer sind im Spiel • Sehr praktisch für alle Situationen, in denen Objekte (POCOs = Plain Old CLR Objects) einfach nur "persistiert" werden sollen
Beispiel für Code-First bei EF 4.1 (1) Klassen besitzen keine Abhängigkeiten Class Person Property Name As StringEnd PersonClass Mitarbeiter : Person<Key()> Property MitarbeiterID As IntegerProperty Reservierungen As Ienumerable(Of Reservierung) Property EinstellDatum As DateTimeEnd ClassClass Reservierung <Key()> Property ReservierungID As Integer Property MitarbeiterID As IntegerEnd ClassClass VBHotelContext : Inherits DBContext Property Mitarbeiter As DBSet(Of Mitarbeiter) Property Reservierungen As DBSet(Of Reservierung)End Class
Beispiel für Code-First bei EF 4.1 (2) Anlegen und Persistieren von Objekten Sub Main Using Db As New VBHotelContext Dim m As New Mitarbeiter With { .Name = "Pemo", .EinstellDatum=Now } Db.Mitarbeiter.Add(m) Db.SaveChanges() End UsingEnd Main Abfragen von Objekten Sub Main Using Db As New VBHotelContext Dim NeueMitarbeiter = From m in Db.Mitarbeiter Where m.EinstellDatum > "1.1.2011" Select m End UsingEnd Main Legt Datenbank via App.config an
EF 4.1 – Die Struktur der Datenbank Namensvergabe kann überschrieben werden
MVVM bei WPF und Silverlight (Schwerpunkt 4) • MVVM = Model View ViewModel • Abgeleitet aus dem klassischen MVC-Muster (Movel View Controller) • Spielt (wegen Datenbindung) nur bei WPF, Silverlight und WP7 eine Rolle • Sinnvolle Abstrahierung der Benutzeroberfläche (Window, UserControl) von den Klassen, die die Daten zur Verfügung stellen
MVVM (1) • Model – eine klassische Datenklasse • ViewModel – kapselt die Datenklasse und macht sie bindungsfähig • View – stellt eine Sicht auf die Datenklasse dar, dessen Daten über das ViewModel gebunden werden
MVVM - Vorteile • Gibt (endlich) eine Antwort auf die Frage, wie eine Anwendung mit Benutzeroberfläche strukturiert wird • Seit Jahren bewährter Ansatz • Praxiserprobt und "Tausendfach" modifiziert • Unterstützung durch Frameworks • Im Grunde für WPF- und Silverlight-Anwendungen der einzige Ansatz
MVVM - Nachteile • Wirkt teilweise recht komplex (ist es aber nur bedingt) • Lernaufwand ist am Anfang sehr groß • Vorteile wirken sich nicht immer direkt aus • Man muss MVVM bereits sehr gut verstanden haben, um keine "Designfehler" zu machen und sich nicht in eine Ecke zu manöverieren • Keine Unterstützung durch Microsoft für WPF (aber für Silverlight)
MVVM lernen • Der Einstieg ist nicht ganz leicht • Es gibt viele Tutorials (auch mit VB-Code) • Wenn sich MVVM-Experten austauschen wird es sehr schnell kompliziert • Trotzdem ist MVVM nicht schwer zu erlernen • Die größte Herausforderung besteht am Anfang darin, den "Sinn" zu erkennen und den Mehraufwand zu akzeptieren
Asynchrone Aufrufe (Schwerpunkt 5) • So war es bislang • So wird es mit Visual Basic 11 sein • Ebenfalls neu bei VB11: Iteratoren
So war es bislang… • Asynchrone Aufrufe sind schwierig zu implementieren • Expliziter Callback erforderlich • Programmlogik wird "zerstückelt" • Threadübergreifender Zugriff von einer asynchron ausgeführten Methode etwas problematisch • Exception-Handling wird meistens ignoriert • Viele VB-Entwickler ließen bislang lieber die Finger davon
Asynchrone Aufrufe – Lösungsansätze • Es gibt verschiedene Lösungsansätze: • Begin<Operation>/End<Operation>-Entwurfsmuster aus .NET 1.x (z.B. FileStream-Klasse) • Auslagern auf einem Backgroundthread aus dem Threadpool • Asynchrone Aufrufe über Delegaten, BeginInvoke und einem Callback • Einige wenige.NET-Methoden sind von Haus aus asynchron und melden sich über ein Event (z.B. DownloadStringAsync der WebClient-Klasse) • Die BackgroundWorker-Komponente (der einfachste Ansatz)
Asynchrone Aufrufe – Schwachpunkte der vorhandenen Ansätze • Erhöhter Implementierungsaufwand • Viele Entwickler schrecken vor Delegaten, asynchronen Callbacks zurück (wirken kompliziert) • Was ist mit vorzeitigem Abbruch oder einer Fortschrittsmeldung? • Die Programmlogik muss angepasst werden • Threads kosten Ressourcen (1 Mbyte Arbeitsspeicher pro Thread)
Asynchrone Aufrufe – Neu: TAP • TAP – Task-basedasynchronous Patterns • Empfehlung von Microsoft für die Umsetzung und den asynchronen Aufruf beliebiger Methoden • Unbedingt das White-Paper lesen http://www.microsoft.com/download/en/details.aspx?id=19957
Asynchrone Aufrufe – TAP im Detail (1) • Basiert auf den mit .NET 4.0 eingeführten Tasks • Ein Task steht für eine Operation (Methode), die vom Task Scheduler ausgeführt wird • Es gibt nur ein Methode • Namenskonvention: <Operation>TaskAsync • Gibt immer ein Task- bzw. Task(Of T)-Objekt zurück