Anpassbare Software mit dem .NET Framework: Compilieren statt interpretieren Ralf Westphal Freier Fachautor & Berater Microsoft Regional Director [email protected].
Download ReportTranscript Anpassbare Software mit dem .NET Framework: Compilieren statt interpretieren Ralf Westphal Freier Fachautor & Berater Microsoft Regional Director [email protected].
Anpassbare Software mit dem .NET Framework: Compilieren statt interpretieren Ralf Westphal Freier Fachautor & Berater Microsoft Regional Director [email protected] Anwendungen anpassen Aussehen/Funktionalität ohne Neuübersetzung ändern • • • Möglicherweise beim Anwender Parametrisierung • Beliebige Anzahl Werte Scripting • Funktionalität mit Algorithmen beschreiben Anpassbarkeit gewinnt an Bedeutung • Anpassen einer Standardapplikation ist meist billiger als Spezialentwicklung Scripte Beschreibung davon „was zu tun ist“ Kein spezifisches Format • • Textuelle Formate • • • Imperative Programmiersprachen (z.B. VBScript) Deklarative Programmiersprachen (z.B. reguläre Ausdrücke, XSLT) Eigene Formate (z.B. XML-basiert) Strukturierte Formate • Relationale Datenbanken (z.B. industrieelle Stücklisten) Beispiele • Reguläre Ausdrücke, ad hoc Ausdrucksberechnung, Validation, Administration, mobile Agenten, Ereignisbehandlung Interpretation Per definitionem werden Scripte interpretiert • • Scriptformat nicht direkt ausführbar Applikation bestimmt „Bedeutung“ von Script/Parametern • Script wird geparst (Erkennung von Anweisungen) • Applikation führt Anweisungen aus, die den Applikationszustand beeinfluss Vorteile • • • Flexibilität Meist einfach zu implementieren Meist einfach zu installieren Nachteile • • Schlechte Performance Scripte sind leicht einzusehen Demo Ausdrucksberechnung Performance Killers Wiederholtes Parsen • • • Textuelle Repräsentation aufbrechen • • Lexikale Analyse (Symbole erkennen) Syntaktische Analyse (Anweisungen erkennen) Typumwandlung • Text in angemessenen Datentyp wandeln Alternative: Spezielle Datenstrukturen traversieren (z.B. Datenbank, XML) Wiederholte Interpretation • Immer wieder bestimmen, was zu tun ist – statt es einfach zu tun Mögliche Verbesserung: • Script einmalig in eine internet Zwischendarstellung wandeln (Abstrakter Syntaxbaum (AST)) Demo Ausdrucksberechnung mit AST Performance Boost Übersetzung in ausführbaren Code • • Einmaliges Parsen Einmalige Interpretation • Resultat: Ausführbarer Code, der einfach das tut, was mit einem Script beabsichtigt war Vorteil • Rohe Geschwindigkeit Nachteil • Schwer zu implementieren Es wie .NET tun... Compilation statt Interpretation Scripte sind überall • • • • Reguläre Ausdrücke XML-Serialisierung ASP.NET Seite XML Web Service Proxy • • XPath Queries XSLT Transformationen Demo RegEx XML-Serialisierung XPath ASP.NET Seite XML Web Service Proxy Es ist einfach! Neue Technologien machen Codegenerierung sehr einfach • • • IL als Fundament CodeDOM • • Sourcecode on-the-fly compilieren AST zur Laufzeit zusammenbauen und compilieren Reflection.Emit • Direkt IL erzeugen Demo Ausdrucksberechnung durch Compilation von Sourcecode mit CodeDOM ... Compilation eines AST ... Ausgabe von IL mit Reflection.Emit (Assertions und Context Attributes) CodeDOM I Sourcecode on-the-fly compilieren Dim vbcp As New VBCodeProvider() Dim vbc As Compiler.ICodeCompiler = vbcp.CreateCompiler Dim cps As New Compiler.CompilerParameters() cps.CompilerOptions = String.Format("/libpath:""{0}"" /rootnamespace:{1}", _ Environment.CurrentDirectory, Me.GetType.Namespace) cps.OutputAssembly = DateTime.Now.Ticks & ".dll" cps.ReferencedAssemblies.Add("System.dll") cps.ReferencedAssemblies.Add("ExpressionEvaluator.dll") Dim cr As Compiler.CompilerResults cr = vbc.CompileAssemblyFromSource(cps, source) CodeDOM II Aufbau eines AST _codeRoot = New CodeNamespace("ralfw.ExpressionEvaluation") _codeRoot.Imports.Add(New CodeNamespaceImport("System")) Dim classCe As New CodeTypeDeclaration("CompiledExpression") classCe.IsClass = True classCe.Attributes = MemberAttributes.Public classCe.BaseTypes.Add("CompiledExpressionBase") _codeRoot.Types.Add(classCe) Dim funcEval As New CodeMemberMethod() funcEval.Name = "Eval" funcEval.Attributes = MemberAttributes.Public Or MemberAttributes.Override funcEval.Parameters.Add(New CodeParameterDeclarationExpression("Double", "x")) funcEval.ReturnType.BaseType = "Double" classCe.Members.Add(funcEval) _stmReturn = New CodeMethodReturnStatement() funcEval.Statements.Add(_stmReturn) Reflection.Emit I IL direkt erzeugen Dim an As New Reflection.AssemblyName() an.Name = "re" & DateTime.Now.Ticks.ToString _asmCompiledExpression = AppDomain.CurrentDomain.DefineDynamicAssembly(an, _ AssemblyBuilderAccess.RunAndSave) _asmFilename = an.Name & ".dll" Dim mb As ModuleBuilder = _asmCompiledExpression.DefineDynamicModule(_asmFilename) _tbCompiledExpression = mb.DefineType("ralfw.ExpressionEvaluation.CompiledExpression", _ TypeAttributes.Public Or TypeAttributes.Class, _ GetType(CompiledExpressionBase)) Dim fb As MethodBuilder = _tbCompiledExpression.DefineMethod("Eval", _ MethodAttributes.Virtual Or MethodAttributes.Public, _ GetType(System.Double), _ New Type() {GetType(System.Double)}) _ilCompiledExpression = fb.GetILGenerator() Bedenkenswertes Lexikalische/syntaktische Analyse immer noch nötig • XML-Formate können hier helfen Am einfachsten geht es mit CodeDOM • • Kann Sourcecode erzeugen/übersetzen Hochsprachenkonstrukte (C# angelehnt) Reflection.Emit bringt Geschwindigkeit • • • Codegenerierung Übersetzung Flexibilität (geht über C#-Konstrukte hinaus) Achtung: Dynamisch erzeugte Assemblies können nicht entladen werden • Abhilfe: Hosting in separater AppDomain Zusammenfassung Compilation ist heute sehr einfach • Compilierte Scripte sind immer schneller als interpretierte Compilierte Scripte sind in 99% der Fälle genauso flexibel Compilation benutzen, wenn Summe aus Übersetzungszeit und Laufzeit < Interpretationszeit • Wenn Sie einen Parser/Interpreter haben, haben Sie es schon fast geschafft Wiederholte Ausführung eines Scripts rechtfertigt allermeistens eine Compilation Oder: Compilieren Sie einfach, weil es cool ist Fragen!? Uff... Ressourcen Saurabh Nandu, Emitting Dynamic Assemblies on the fly using Reflection.Emit, Wrox Press, www.csharptoday.com Peter Huene, Exploring the System.Reflection.Emit Namespace, http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=238 Brian J. Korzeniowski, Microsoft .NET CodeDom Technology - Part 1-3, http://www.15seconds.com/issue/020917.htm Paul Nichols, CodeDOM: How to achieve code generation in .NET, http://www.devcity.net/net/article.aspx?alias=codedom_1 Nick Harrison, Using the CodeDOM, http://www.ondotnet.com/lpt/a/3155 Tom Archer, Andrew Whitechapel, String Handling and Regular Expressions, in: Inside C#, MSPress, http://www.microsoft.com/mspress/books/sampchap/5861b.asp Beispiele: Über den Referenten Ralf Westphal ist freier Softwaretechnologievermittler. Er arbeitet als Fachautor, Coach/Berater, Softwareentwickler und Sprecher auf Konferenzen im In- und Ausland wie Microsoft Technical Summit, XML-in-Action, BASTA!, COMDEX, Software Development oder XML One. Der Schwerpunkt seiner Arbeit liegt bei der Vermittlung und Anwendung moderner Softwaretechnologien und -konzepte auf der Microsoft Plattform mit Fokus in den Bereichen OOP/komponentenorientierte Entwicklung, Softwarearchitektur und .NET Framework. Darüber hinaus ist Ralf Westphal einer der deutschen Microsoft MSDN Regional Directors, Mitglied verschiedener Fachbeiräte und war von 1998 bis 2001 Chefredakteur der Visual Basic Fachzeitschrift BasicPro. Bücher des Referenten .NET kompakt 140 Seiten, Spektrum Akademischer Verlag, 2002, ISBN 3827411858 ADO.NET Datenbankprogrammierung 130 Seiten , Addison-Wesley , 2002 , ISBN 3827319978 Jetzt lerne ich ADO.NET Einfache Datenbankprogrammierung im .NETFramework 400 Seiten, Markt+Technik, 2003, ISBN 3827262291 (erscheint im September) Empower people through great software any time, any place, and on any device